JAVA中常用的XML文件解析工具有三个,DOM、SAX和PULL,DOM解析需要将整个XML文件读入内存,不适合android,SAX和PULL都比较小巧合适,这篇博文以SAX方法为例,解析一个本地的XML文件,将结果存入对象列表,还可以将对象列表里的数据以XML文件写出。
解析类结构:Worker.java
package fk.androiddemo_010;
/**
* Created by Administrator on 2016/9/19.
*/
public class Worker {
private String id;
private String name;
private int age;
private String sex;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "id:" + id + ", name:" + name + ", age:" + age+", sex:" + sex;
}
}
XML文件:test.xml(此文件位于res/raw文件夹下)
<?xml version="1.0" encoding="utf-8"?>
<workers>
<worker id="001">
<name>汤姆</name>
<age>18</age>
<sex>男</sex>
</worker>
<worker id="002">
<name>杰瑞</name>
<age>19</age>
<sex>男</sex>
</worker>
<worker id="003">
<name>莉莉</name>
<age>17</age>
<sex>女</sex>
</worker>
</workers>
解析工具类:SexWorkerParser.java
package fk.androiddemo_010;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
/**
* Created by Administrator on 2016/9/19.
*/
public class SexWorkerParser {
public class MyHandler extends DefaultHandler {
private List<Worker> workers;
private Worker worker;
private StringBuilder builder;
@Override
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("......startParseXML......");
workers = new ArrayList<>();
builder = new StringBuilder();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
System.out.println("**startOneElement**");
System.out.println("localName=" + localName + " qName=" + qName);//有的元素名字有前缀,加上前缀后的为qName
if (localName.equals("worker")) {
worker = new Worker();
for(int i=0;i<attributes.getLength();i++){//循环获取元素的所有属性
if(attributes.getLocalName(i).equals("id"))
worker.setId(attributes.getValue(i));
}
}
builder.setLength(0);//将字符长度设置为0 以便重新开始读取元素的内容
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
System.out.println("**characters**");
builder.append(ch, start, length); //将读取的字符数组追加到builder中
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
System.out.println("**endOneElement**");
if (localName.equals("name")) {
worker.setName(builder.toString());
} else if (localName.equals("age")) {
worker.setAge(Integer.parseInt(builder.toString()));
} else if (localName.equals("sex")) {
worker.setSex(builder.toString());
} else if (localName.equals("worker")) {
workers.add(worker);
}
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
System.out.println("......endParseXML......");
}
//返回解析后得到的Book对象集合
public List<Worker> getWorkers() {
return workers;
}
}
//解析函数
public List<Worker> parse(InputStream is) throws Exception {
SAXParserFactory factory = SAXParserFactory.newInstance(); //取得SAXParserFactory实例
SAXParser parser = factory.newSAXParser(); //从factory获取SAXParser实例
MyHandler handler = new MyHandler(); //实例化自定义Handler
parser.parse(is, handler); //根据自定义Handler规则解析输入流
return handler.getWorkers();
}
//反解析函数
public String serialize(List<Worker> workers) throws Exception {
SAXTransformerFactory factory = (SAXTransformerFactory) TransformerFactory.newInstance();//取得SAXTransformerFactory实例
TransformerHandler handler = factory.newTransformerHandler(); //从factory获取TransformerHandler实例
Transformer transformer = handler.getTransformer(); //从handler获取Transformer实例
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); // 设置输出采用的编码方式
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); // 是否忽略XML声明
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); // 是否首行缩进
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");//首行缩进四个字符
StringWriter writer = new StringWriter();
Result result = new StreamResult(writer);
handler.setResult(result);
String uri = ""; //代表命名空间的URI 当URI无值时 须置为空字符串
String localName = ""; //命名空间的本地名称(不包含前缀) 当没有进行命名空间处理时 须置为空字符串
handler.startDocument();
handler.startElement(uri, localName, "workers", null);
AttributesImpl attrs = new AttributesImpl(); //负责存放元素的属性信息
char[] ch = null;
for (Worker worker : workers) {
attrs.clear(); //清空属性列表
//添加一个名为id的属性(type影响不大,这里设为string)
attrs.addAttribute(uri, localName, "id", "string", String.valueOf(worker.getId()));
handler.startElement(uri, localName, "worker", attrs); //开始一个worker元素 关联上面设定的id属性
handler.startElement(uri, localName, "name", null); //开始一个name元素 没有属性
ch = String.valueOf(worker.getName()).toCharArray();
handler.characters(ch, 0, ch.length); //设置name元素的文本节点
handler.endElement(uri, localName, "name");
handler.startElement(uri, localName, "age", null);//开始一个price元素 没有属性
ch = String.valueOf(worker.getAge()).toCharArray();
handler.characters(ch, 0, ch.length); //设置price元素的文本节点
handler.endElement(uri, localName, "age");
handler.startElement(uri, localName, "sex", null);//开始一个price元素 没有属性
ch = String.valueOf(worker.getSex()).toCharArray();
handler.characters(ch, 0, ch.length); //设置price元素的文本节点
handler.endElement(uri, localName, "sex");
handler.endElement(uri, localName, "worker");
}
handler.endElement(uri, localName, "workers");
handler.endDocument();
String res=writer.toString();//发现XML声明和下面的内容没有换行,所以下面加了个换行符
return res.substring(0,38)+"\n"+res.substring(38,res.length());
}
}
主界面:mainActivity
package fk.androiddemo_010;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity implements View.OnClickListener{
private static final String TAG = "XML";
Button parseXmlBut,writeXmlBut ;
SexWorkerParser parser;
List<Worker> workers;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parseXmlBut=(Button)findViewById(R.id.parseXmlBut);
parseXmlBut.setOnClickListener(this);
writeXmlBut=(Button)findViewById(R.id.writeXmlBut);
writeXmlBut.setOnClickListener(this);
workers=new ArrayList<>();
}
@Override
public void onClick(View v) {
if(v==parseXmlBut){
parser = new SexWorkerParser(); //创建SaxBookParser实例
//打开XML文件
InputStream fileData=getResources().openRawResource(R.raw.test);
try {
workers = parser.parse(fileData); //解析输入流
for (Worker worker : workers) {
System.out.println(worker.toString());
}
} catch (Exception e) {
System.out.println("???"+e);
}
}else{
try {
String xml = parser.serialize(workers); //序列化
System.out.println(xml);
//这个文件会建立在 data/data/项目名称/files 下
FileOutputStream fos = openFileOutput("books2.xml", Context.MODE_PRIVATE);
fos.write(xml.getBytes("UTF-8"));
fos.flush();
fos.close();
//这个文件会建立在手机外部存储根目录下(需要申请权限)
File file = new File(Environment.getExternalStorageDirectory()
+ File.separator+ "books3.xml");
if( !file.exists()) file.createNewFile();
FileOutputStream stream = new FileOutputStream(file);
stream.write(xml.getBytes("UTF-8"));
fos.flush();
stream.close();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
}
}
最后需要申请下读写外部存储权限:
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>