Xml解析

来源:互联网 发布:刘强东脸盲 知乎 编辑:程序博客网 时间:2024/06/05 05:08

XML解析在Android中应用的比较多,很多时候存储数据需要使用到XML。

这里介绍四种XML解析方式,很多地方说是三种xml解析方式(除去第一种原生xml解析),但是这里的XmlResourceParser跟其他三种不知道是否重复:

1、原生XML解析:XmlResourceParser

2、SAX解析器,

3、DOM解析器,

4、PULL解析器

公共接口:

public interface BookParser {    //解析输入流,得到book对象集合    public List<Book> parse(InputStream is) throws Exception;    //序列化Book对象集合,得到xml形式字符串    public String serialize(List<Book> books) throws Exception;}

公共实体类:

package com.mfc.xmlutils;/** * Created by Administrator on 2017/8/11. */public class Book {    private int id;    private String name;    private float price;    public Book() {    }    public Book(int id, String name, float price) {        this.id = id;        this.name = name;        this.price = price;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public float getPrice() {        return price;    }    public void setPrice(float price) {        this.price = price;    }    @Override    public String toString() {        return "Book{" +                "id=" + id +                ", name='" + name + '\'' +                ", price=" + price +                '}';    }}


一、原生XML解析:XmlResourceParser

books.xml:(这个xml存放在res的xml文件夹里):

<?xml version="1.0" encoding="utf-8"?><books>    <book price="1.0" id="1001">Java</book>    <book price="89.0" id="1002">Java EE</book>    <book price="69.0" id="1003">Ajax</book></books>


工具类:

package com.mfc.xmlutils;import android.content.Context;import android.content.res.XmlResourceParser;import com.example.administrator.parsexml.R;import java.util.ArrayList;import java.util.List;public class XmlResourceParserUtil {    private Context context;    public XmlResourceParserUtil(Context context){        this.context = context;    }    public List<Book> getXmlResource(){        XmlResourceParser xlp = context.getResources().getXml(R.xml.books);        try {            List<Book> books = new ArrayList<Book>();            Book book = null;            //循环,如果还没有到xml文档的结尾处            while (xlp.getEventType() != XmlResourceParser.END_DOCUMENT){                //如果遇到了开始标签                if (xlp.getEventType() == XmlResourceParser.START_TAG){                    //获取标签名                    String tagName = xlp.getName();                    //如果遇到Book标签                    if (tagName.equals("book")){                        book = new Book();                        //根据属性名来获取属性值                        String bookPrice = xlp.getAttributeValue(0);                        book.setPrice(Float.parseFloat(bookPrice));                        String id = xlp.getAttributeValue(1);                        book.setId(Integer.parseInt(id));                        //获取文本节点的值                        book.setName(xlp.nextText());                        books.add(book);                    }                }                xlp.next();            }            return books;        } catch (Exception e) {            e.printStackTrace();        }        return null;    }}

activity:

parserButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                XmlResourceParserUtil xmlResourceParserUtil = new XmlResourceParserUtil(SAXParserXmlActivity.this);                List<Book> books = xmlResourceParserUtil.getXmlResource();                StringBuilder stringBuilder = new StringBuilder();                for (Book book : books) {                    stringBuilder.append(book.toString());                }                XMLContent.setText(stringBuilder.toString());             }        });

二、SAX解析器:

books.xml(这个xml存放在assets文件夹下):以下几种解析xml的方法都使用的这一个xml

<?xml version="1.0" encoding="utf-8"?><books>    <book>        <id>1001</id>        <name>java编程思想</name>        <price>80.00</price>    </book>    <book>        <id>1002</id>        <name>Android群英传</name>        <price>90.00</price>    </book>    <book>        <id>1003</id>        <name>spring源码解析</name>        <price>100.00</price>    </book></books>


工具类:

package com.mfc.xmlutils;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 2017/8/11. */public class BookSaxParser implements BookParser {    @Override    public List<Book> parse(InputStream is) throws Exception {        //取得SAXParserFactory实例        SAXParserFactory factory = SAXParserFactory.newInstance();        //从factory获取SAXParser实例        SAXParser parser = factory.newSAXParser();        //实例化自定义的Handler        MyHandler myHandler = new MyHandler();        parser.parse(is,myHandler);        return myHandler.getBooks();    }    @Override    public String serialize(List<Book> books) throws Exception {        //取得SAXTransformerFactory实例        SAXTransformerFactory factory = (SAXTransformerFactory) TransformerFactory.newInstance();        //从factory获取TransformerHandler实例        TransformerHandler handler = factory.newTransformerHandler();        //从handler获取Transformer实例        Transformer transformer = handler.getTransformer();        //设置输出采用的编码方式        transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");        //是否自动添加额外的空白        transformer.setOutputProperty(OutputKeys.INDENT,"yes");        //是否忽略xml声明        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"no");        StringWriter writer = new StringWriter();        Result result = new StreamResult(writer);        handler.setResult(result);        //代表命名空间的URI,当URI无值时,需设置为空字符串        String uri = "";        //命名空间的本地名称(不包含前缀),当没有进行命名空间处理时,需要设置为空字符串        String localName = "";        handler.startDocument();;        handler.startElement(uri,localName,"books",null);        //负责存放元素的属性信息        AttributesImpl attrs = new AttributesImpl();        char[] ch = null;        for (Book book : books){            //清空属性列表            attrs.clear();            //添加一个名为id的属性(type影响不大,这里设置为String)            attrs.addAttribute(uri,localName,"id","string",String.valueOf(book.getId()));            //开始一个book元素,关联上面设定的id属性            handler.startElement(uri,localName,"book",attrs);            //开始一个那么属性,没有元素            handler.startElement(uri,localName,"name",null);            ch = String.valueOf(book.getName()).toCharArray();            //设置price元素的文本节点            handler.characters(ch,0,ch.length);            handler.endElement(uri,localName,"price");            handler.endElement(uri,localName,"book");        }        handler.endElement(uri,localName,"books");        handler.endDocument();        return writer.toString();    }    //需要重写DefaultHandler的方法    private class MyHandler extends DefaultHandler{        private List<Book> books;        private Book book;        private StringBuilder builder;        //返回解析后得到的Book对象集合        public List<Book> getBooks() {            return books;        }        //初始化        @Override        public void startDocument() throws SAXException {            super.startDocument();            books = new ArrayList<Book>();            builder = new StringBuilder();        }        @Override        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {            super.startElement(uri, localName, qName, attributes);            //开始如果遇到了book标签,就新建一个Book对象            if (localName.equals("book")) {                book = new Book();            }            //将字符长度设置为0,一边重新开始读取元素的字符节点            builder.setLength(0);        }        @Override        public void characters(char[] ch, int start, int length) throws SAXException {            super.characters(ch, start, length);            //将读取的字符数组追加到builder中            builder.append(ch,start,length);        }        @Override        public void endElement(String uri, String localName, String qName) throws SAXException {            super.endElement(uri, localName, qName);            //遇到book标签后,接下来将遇到的标签对应的值放进实体类对应的属性里面            if (localName.equals("id")){                book.setId(Integer.parseInt(builder.toString()));            }else if (localName.equals("name")) {                book.setName(builder.toString());            }else if (localName.equals("price")) {                book.setPrice(Float.parseFloat(builder.toString()));            }else if (localName.equals("book")) {                books.add(book);            }        }    }}

activity:

 parserXmlBySAXButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                try {                    InputStream is = getAssets().open("books.xml");                    //创建SaxBookParser实例                    parserSAX = new BookSaxParser();                    //解析输入流                    books = parserSAX.parse(is);                    StringBuilder stringBuilder = new StringBuilder();                    for (Book book : books) {                        stringBuilder.append(book.toString());                    }                    XMLContent.setText(stringBuilder.toString());                } catch (Exception e) {                    e.printStackTrace();                }            }        });        writerXmlBySAXButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                try {                    String xml = parserSAX.serialize(books);                    FileOutputStream fos = openFileOutput("books.xml", Context.MODE_PRIVATE);                    fos.write(xml.getBytes("UTF-8"));                    Toast.makeText(SAXParserXmlActivity.this, "写入成功",Toast.LENGTH_LONG).show();                } catch (Exception e) {                    e.printStackTrace();                }            }        });

三、DOM解析器:

工具类:

package com.mfc.xmlutils;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import java.io.InputStream;import java.io.StringWriter;import java.util.ArrayList;import java.util.List;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.transform.OutputKeys;import javax.xml.transform.Result;import javax.xml.transform.Source;import javax.xml.transform.Transformer;import javax.xml.transform.TransformerFactory;import javax.xml.transform.dom.DOMSource;import javax.xml.transform.stream.StreamResult;/** * Created by Administrator on 2017/8/12. */public class BookDomParser implements BookParser {    @Override    public List<Book> parse(InputStream is) throws Exception {        List<Book> books = new ArrayList<Book>();        //获取DocumentBuilderFactory实例        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();        //从factory获取DocumentBuilder实例        DocumentBuilder builder = factory.newDocumentBuilder();        //解析输入流,得到Document实例        Document doc = builder.parse(is);        Element rootElement = doc.getDocumentElement();        NodeList items = rootElement.getElementsByTagName("book");        for (int i=0;i<items.getLength();i++) {            Book book = new Book();            Node item = items.item(i);            NodeList properties = item.getChildNodes();            for (int j = 0;j<properties.getLength();j++) {                Node property = properties.item(j);                String nodeName = property.getNodeName();                if(nodeName.equals("id")){                    book.setId(Integer.parseInt(property.getFirstChild().getNodeValue()));                } else if (nodeName.equals("name")) {                    book.setName(property.getFirstChild().getNodeValue());                } else if (nodeName.equals("price")) {                    book.setPrice(Float.parseFloat(property.getFirstChild().getNodeValue()));                }            }            books.add(book);        }        return books;    }    @Override    public String serialize(List<Book> books) throws Exception {        //获取DocumentBuilderFactory对象        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();        DocumentBuilder builder = factory.newDocumentBuilder();        //由builder创建新文档        Document doc = builder.newDocument();        Element rootElement = doc.createElement("books");        for (Book book : books) {            Element bookElement = doc.createElement("book");            bookElement.setAttribute("id",book.getId()+"");            Element nameElement = doc.createElement("name");            nameElement.setTextContent(book.getName());            bookElement.appendChild(nameElement);            Element priceElement = doc.createElement("price");            priceElement.setTextContent(book.getPrice()+"");            bookElement.appendChild(priceElement);            rootElement.appendChild(bookElement);        }        doc.appendChild(rootElement);        //取得TransformerFactory实例        TransformerFactory transFactory = TransformerFactory.newInstance();        //从transFactory获取Transformer实例        Transformer transformer = transFactory.newTransformer();        //设置输出采用的编码方式        transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");        //设置自动添加额外的空白        transformer.setOutputProperty(OutputKeys.INDENT,"yes");        //设置忽略xml声明        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"no");        StringWriter writer = new StringWriter();        //表明文档来源是doc        Source source = new DOMSource(doc);        //表明目标结果为writer        Result result = new StreamResult(writer);        //开始转换        transformer.transform(source,result);        return writer.toString();    }}

activity:

parserXmlByDOMButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                try {                    InputStream is = getAssets().open("books.xml");                    //创建SaxBookParser实例                    parserDOM = new BookDomParser();                    //解析输入流                    books = parserDOM.parse(is);                    StringBuilder stringBuilder = new StringBuilder();                    for (Book book : books) {                        stringBuilder.append(book.toString());                    }                    XMLContent.setText(stringBuilder.toString());                } catch (Exception e) {                    e.printStackTrace();                }            }        });        writerXmlByDOMButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                try {                    String xml = parserDOM.serialize(books);                    FileOutputStream fos = openFileOutput("books.xml", Context.MODE_PRIVATE);                    fos.write(xml.getBytes("UTF-8"));                    Toast.makeText(SAXParserXmlActivity.this, "写入成功",Toast.LENGTH_LONG).show();                } catch (Exception e) {                    e.printStackTrace();                }            }        });

四、PULL解析器

工具类:

package com.mfc.xmlutils;import android.util.Xml;import org.xmlpull.v1.XmlPullParser;import org.xmlpull.v1.XmlSerializer;import java.io.InputStream;import java.io.StringWriter;import java.util.ArrayList;import java.util.List;/** * Created by Administrator on 2017/8/12. */public class BookPullParser implements BookParser {    @Override    public List<Book> parse(InputStream is) throws Exception {        List<Book> books = null;        Book book = null;        //从android.util.Xml创建一个XmlPullParser实例        XmlPullParser parser = Xml.newPullParser();        //设置输入流,并指明编码方式        parser.setInput(is,"UTF-8");        int eventType = parser.getEventType();        while(eventType != XmlPullParser.END_DOCUMENT){            switch (eventType){                case XmlPullParser.START_DOCUMENT:                    books = new ArrayList<Book>();                    break;                case XmlPullParser.START_TAG:                    if (parser.getName().equals("book")) {                        book = new Book();                    }else if (parser.getName().equals("id")){                        eventType = parser.next();                        book.setId(Integer.parseInt(parser.getText()));                    }else if (parser.getName().equals("name")){                        eventType = parser.next();                        book.setName(parser.getText());                    }else if (parser.getName().equals("price")){                        eventType = parser.next();                        book.setPrice(Float.parseFloat(parser.getText()));                    }                    break;                case XmlPullParser.END_TAG:                    if (parser.getName().equals("book")){                        books.add(book);                        book = null;                    }                    break;            }            eventType = parser.next();        }        return books;    }    @Override    public String serialize(List<Book> books) throws Exception {        //由android.util.Xml创建一个XmlSerializer实例        XmlSerializer serializer = Xml.newSerializer();        StringWriter writer = new StringWriter();        //设置输出方式为writer        serializer.setOutput(writer);        serializer.startDocument("UTF-8",true);        serializer.startTag("","books");        for (Book book : books) {            serializer.startTag("","book");            serializer.attribute("","id",book.getId()+"");            serializer.startTag("","name");            serializer.text(book.getName());            serializer.endTag("","name");            serializer.startTag("", "price");            serializer.text(book.getPrice() + "");            serializer.endTag("", "price");            serializer.endTag("", "book");        }        serializer.endTag("", "books");        serializer.endDocument();        return writer.toString();    }}

activity:

parserXmlByPULLButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                try {                    InputStream is = getAssets().open("books.xml");                    //创建SaxBookParser实例                    parserPULL = new BookDomParser();                    //解析输入流                    books = parserPULL.parse(is);                    StringBuilder stringBuilder = new StringBuilder();                    for (Book book : books) {                        stringBuilder.append(book.toString());                    }                    XMLContent.setText(stringBuilder.toString());                } catch (Exception e) {                    e.printStackTrace();                }            }        });        writerXmlByPULLButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                try {                    String xml = parserPULL.serialize(books);                    FileOutputStream fos = openFileOutput("books.xml", Context.MODE_PRIVATE);                    fos.write(xml.getBytes("UTF-8"));                    Toast.makeText(SAXParserXmlActivity.this, "写入成功",Toast.LENGTH_LONG).show();                } catch (Exception e) {                    e.printStackTrace();                }            }        });

效果图(这里由于使用的真机,所以看不到写入的文件):


对于这几种解析器各有优点,更倾向于PULL解析器,因为SAX解析器操作起来太笨重,DOM不适合文档较大,内存较小的场景,唯有PULL轻巧灵活,速度快,占用内存小,使用非常顺手。


源码下载:http://download.csdn.net/download/fancheng614/9931088