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"/>