End

XML 解析 DOM SAX PULL 序列化

本文地址


目录

XML 解析

Android 中默认已经引入 XmlPull,如果需要自己引入,需要同时添加 1.1.41.1.3.4-O 两个 jar 包。

几种解析方式简介

  • DOM 解析:将xml文件全部载入到内存,组装成一棵dom树,然后通过节点以及节点之间的关系来解析xml文件;理解较简单,但是由于整个文档都需要载入内存,不适用于文档较大时。
  • SAX 解析:基于事件驱动,逐条解析,适用于只处理xml数据;不易编码,而且很难同时访问同一个文档中的多处不同数据。
  • JDOM 解析:主要用来弥补 DOM 和 SAX 在实际应用当中的不足,比使用 DOM 实现更快,仅使用具体类而不使用接口,因此简化了API,并且易于使用。
  • DOM4j 解析:JDOM的一种智能分支,功能较强大,建议熟练使用。
  • Pull 解析:Android提供的一种解析方式,与 SAX 解析器相似,基于事件驱动逐条解析,但需要使用parser.next()方法来提取它们。

Pull 解析和 Sax 解析比较

Pull 解析和 Sax 解析在运行方式上具有相似性,Pull 解析器也提供了类似 SAX 的事件,开始文档START_DOCUMENT和结束文档END_DOCUMENT,开始元素START_TAG和结束元素END_TAG等,但需要调用next()方法提取它们(主动提取事件)。

SAX 解析器的工作方式是自动将事件推入注册的事件处理器进行处理,因此你不能控制事件的处理主动结束;而Pull解析器的工作方式为允许你的应用程序代码主动从解析器中获取事件,正因为是主动获取事件,因此可以在满足了需要的条件后不再获取事件,结束解析。这是他们主要的区别。

即:SAX 解析会对整个文档进行解析,而 Pull 解析可以在程序中控制解析到哪里就可以中途停止。

测试案例

要解析的内容

<?xml version="1.0" encoding="utf-8"?>
<class>
  <string name="user">包青天</string>
  <string name="job" id="10086">Android开发</string>
  <student id="10010">
    <string name="user">白乾涛</string>
    <string name="job" id="100">码农</string>
  </student>
</class>

DOM 解析

public static void domParseXml(String path) throws Exception {
    System.out.println("--------------------  DOM解析  --------------------");
    Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(path);
    NodeList stringList = document.getElementsByTagName("string");
    domParseNode(stringList); //长度为4【user:包青天, null】【job:Android开发, 10086】【user:白乾涛, null】【job:码农, 100】

    NodeList studentList = document.getElementsByTagName("student");
    System.out.println("【" + studentList.getLength() + "】");

    for (int i = 0; i < studentList.getLength(); i++) {
        NamedNodeMap map = studentList.item(i).getAttributes();
        String id = map != null && map.getNamedItem("id") != null ? map.getNamedItem("id").getNodeValue() : null;
        System.out.println("id = " + id);

        NodeList childNodeList = studentList.item(i).getChildNodes();
        domParseNode(childNodeList); //长度为5(而不是2)【user:白乾涛, null】【job:码农, 100】
    }
}

private static void domParseNode(@NotNull NodeList nodeList) {
    System.out.println("【" + nodeList.getLength() + "】");
    for (int i = 0; i < nodeList.getLength(); i++) {
        Node node = nodeList.item(i);  //获取第i个节点
        if (node != null && node.getFirstChild() != null) {
            NamedNodeMap map = node.getAttributes(); //获取此节点的所有属性
            if (map != null) {
                Node nameNode = map.getNamedItem("name"); //获取名为name的属性
                String nameNodeValue = nameNode != null ? nameNode.getNodeValue() : null; //获取属性的属性值,也可以使用getTextContent
                String nodeValue = node.getFirstChild().getNodeValue(); //获取节点的值

                Node idNode = map.getNamedItem("id"); //获取名为id的属性
                String idNodeValue = idNode != null ? idNode.getNodeValue() : null;
                System.out.println(nameNodeValue + ":" + nodeValue + ", " + idNodeValue);
            }
        }
    }
}
--------------------  DOM 解析  --------------------
【4】
user:包青天, null
job:Android开发, 10086
user:白乾涛, null
job:码农, 100
【1】
id = 10010
【5】
user:白乾涛, null
job:码农, 100

SAX 解析

System.out.println("--------------------  SAX解析  --------------------");
SAXParserFactory.newInstance().newSAXParser().parse(path, new SAXParseHandel());
public class SAXParseHandel extends DefaultHandler {

    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        System.out.println("开始解析");
    }

    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
        System.out.println("结束解析");
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        //开始解析节点时调用此方法
        System.out.println("开始解析" + qName);

        for (int i = 0; i < attributes.getLength(); i++) {
            System.out.println("     " + attributes.getQName(i) + ":" + attributes.getValue(i));//此案例中:getLocalName和getQName一致 ,getType的值为CDATA
        }

        switch (qName) {
        case "student":
            int index = attributes.getIndex("id");//当节点名为student时,获取student的id属性
            System.out.println("   --" + attributes.getQName(index) + ":" + attributes.getValue(index));
            break;
        case "string":
            System.out.print("  -" + attributes.getValue(attributes.getIndex("name")) + ":");
            break;
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
        //节点解析完毕时调用此方法
        System.out.println("结束解析" + qName);
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        //此方法用来获取节点的值
        String value = new String(ch, start, length).trim();
        if (!value.equals("")) {
            System.out.println(value);
        }
    }
}
--------------------  SAX 解析  --------------------
开始解析
开始解析class
开始解析string
     name:user
  -user:包青天
结束解析string
开始解析string
     name:job
     id:10086
  -job:Android开发
结束解析string
开始解析student
     id:10010
   --id:10010
开始解析string
     name:user
  -user:白乾涛
结束解析string
开始解析string
     name:job
     id:100
  -job:码农
结束解析string
结束解析student
结束解析class
结束解析

JDOM 解析

public static void jdomParseXml(String path) throws Exception {
    System.out.println("--------------------  JDOM解析  --------------------");
    org.jdom2.Document document = new SAXBuilder().build(path);
    List<org.jdom2.Element> elementList = document.getRootElement().getChildren();

    for (org.jdom2.Element element : elementList) {
        jdomParseNode(element);

        //解析子节点
        for (org.jdom2.Element chileElement : element.getChildren()) {
            jdomParseNode(chileElement);
        }
    }
}

private static void jdomParseNode(@NotNull org.jdom2.Element element) {
    System.out.println(element.getName() + ":" + element.getTextTrim());

    //解析属性
    List<org.jdom2.Attribute> attributeList = element.getAttributes();
    for (org.jdom2.Attribute attribute : attributeList) {
        System.out.println("    " + attribute.getName() + ":" + attribute.getValue());
    }
}
--------------------  JDOM 解析  --------------------
string:包青天
    name:user
string:Android开发
    name:job
    id:10086
student:
    id:10010
string:白乾涛
    name:user
string:码农
    name:job
    id:100

DOM4J 解析

public static void dom4JParseXml(String path) throws Exception {
    System.out.println("--------------------  DOM4J解析  --------------------");
    org.dom4j.Document document = new SAXReader().read(path);
    Iterator iterator = document.getRootElement().elementIterator();

    while (iterator.hasNext()) {
        org.dom4j.Element element = (org.dom4j.Element) iterator.next();
        dom4JParseNode(element);

        //遍历子节点
        Iterator childIterator = element.elementIterator();
        while (childIterator.hasNext()) {
            dom4JParseNode((org.dom4j.Element) childIterator.next());
        }
    }
}

private static void dom4JParseNode(@NotNull org.dom4j.Element element) {
    System.out.println(element.getName() + ":" + element.getTextTrim());

    //解析属性
    for (Object object : element.attributes()) {
        org.dom4j.Attribute attribute = (org.dom4j.Attribute) object;
        System.out.println("    " + attribute.getName() + ":" + attribute.getValue());
    }
}
--------------------  DOM4J 解析  --------------------
string:包青天
    name:user
string:Android开发
    name:job
    id:10086
student:
    id:10010
string:白乾涛
    name:user
string:码农
    name:job
    id:100

PULL 解析

public static void pullParseXml(String path) throws Exception {
    System.out.println("--------------------  PULL解析  --------------------");
    InputStream inputStream = new FileInputStream(path);
    XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();

    parser.setInput(inputStream, "UTF-8");
    int eventType = parser.getEventType();
    while (eventType != XmlPullParser.END_DOCUMENT) { //文档结束
        switch (eventType) {
        case XmlPullParser.START_TAG://开始标签
            String name = parser.getName();
            System.out.println("开始解析 " + name + ", 行列:" + parser.getLineNumber() + "-" + parser.getColumnNumber() + ", 深度:" + parser.getDepth());
            for (int i = 0; i < parser.getAttributeCount(); i++) {
                //getAttributeType为【CDATA】,getAttributePrefix为【null】,getAttributeNamespace为空【】
                System.out.println("     " + parser.getAttributeName(i) + ":" + parser.getAttributeValue(i));//属性名及属性值
            }

            if ("string".equals(name)) {
                System.out.println(parser.nextText()); //获取节点的值
            }
            break;
        case XmlPullParser.END_TAG://结束标签
            System.out.println("结束解析" + parser.getName());
            break;
        }
        eventType = parser.next();//这一步很重要,该方法返回一个事件码,也是触发下一个事件的方法
    }
}
--------------------  PULL 解析  --------------------
开始解析 class, 行列:2-8, 深度:1
开始解析 string, 行列:3-23, 深度:2
     name:user
包青天
开始解析 string, 行列:4-33, 深度:2
     name:job
     id:10086
Android开发
开始解析 student, 行列:5-23, 深度:2
     id:10010
开始解析 string, 行列:6-25, 深度:3
     name:user
白乾涛
开始解析 string, 行列:7-33, 深度:3
     name:job
     id:100
码农
结束解析student
结束解析class

2019-11-23

posted @ 2019-11-23 21:03  白乾涛  阅读(714)  评论(0编辑  收藏  举报