DOM解析手册

假如想象 提交于 2020-01-06 15:33:53

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

JAVA解析XML手册

XML文档以层级标签的形式来组织数据,多用于配置文件、存储静态数据、交换数据。

XML文档解析

首先我们要知道,“XML中的内容都是结点”,这句话的意思是:XML文档中,无论是 <> </> 符号的里面的内容(属性)、之间的内容(结点值)、还是 <> 本身(结点),都是Node,就连标签之间的换行、空格都是一个节点。明白这个很重要,因为下面遍历结点时,返回的 属性名值对 、结点值内容、结点本身 都是一个Node类型。

实例

解析下面的XML文档

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<users>
    <user userId="1001" idcard="370826199001133290">
        <name>张三</name>
        <address>广州</address>
        <age>18</age>
    </user>
    <user userId="1002" idcard="370826199001133291">
        <name>李四</name>
        <address>大连</address>
        <age>19</age>
    </user>
​
    <user userId="1003" idcard="370826199001133292">
        <name>王五</name>
        <address>广州</address>
        <age>20</age>
    </user>
​
    <user userId="1004" idcard="370826199001133293">
        <age>21</age>
        <address>广州</address>
        <name>冯六</name>
    </user>
</users>

DOM解析

DOM是html和xml的应用程序接口(API),以层次结构(类似于树型)来组织节点和信息片段,映射XML文档的结构,允许获取和操作文档的任意部分,是W3C的官方标准

原理

首先在内存中创建一个Document对象,然后把XML文档读取进来赋值给这个dom对象。由于dom对象是基于树结构的,所以对dom对象进行遍历即可。对内存中的dom对象可以进行查询、修改、删除操作,还可以写回原XML文档保存修改。

【优点】 ①允许应用程序对数据和结构做出更改。 ②访问是双向的,可以在任何时候在树中上下导航,获取和操作任意部分的数据。 【缺点】 ①整个文档必须一次性解析完。

②由于整个文档都需要载入内存,对于大文档成本高。

DOM解析详解

操作步骤:

1:创建DocumentBuilderFactory,由newInstance()方法获取工厂实例;

2:由工厂创建DocumentBuilder;

3:通过 Document dom=builder.parse(file); 读取xml文档创建dom对象;

4:通过dom对象的一系列方法获取某个结点、某名字的结点列表:

Element getElementById(String elementId) 
          返回具有带给定值的 ID 属性的 Element。 
 NodeList getElementsByTagName(String tagname) 
          按文档顺序返回包含在文档中且具有给定标记名称的所有 Element 的 NodeList。

5:通过NodeList对象获取结点列表中某个结点:

Node item(int index) 
          返回集合中的第 index 个项。

6:通过Node对象读取结点属性:

NamedNodeMap getAttributes() 
          包含此节点的属性的 NamedNodeMap(如果它是 Element);否则为 null。

然后对NamedNodeMap对象调用以下方法获取属性:(前面我们说过,属性也是结点)

Node  getNamedItem(String name) 
          检索通过名称指定的节点。
      或
 Node item(int index) 
          返回映射中第 index 个项。

最后,对返回的属性通过以下方法获取名、值:(属性也是结点)

String getNodeName() 
          此节点的名称,取决于其类型; 
​
 String getNodeValue() 
          此节点的值,取决于其类型;

7:获取结点的子节点列表:

NodeList getChildNodes() 
          包含此节点的所有子节点的 NodeList。

8:获取结点值:

String getNodeName() 
          此节点的名称,取决于其类型; 
​
 String getNodeValue() 
          此节点的值,取决于其类型;

总结:DOM方法解析XML文档,把元素、元素属性、元素值都看作Node类型,通过node.getNodeName()获取元素名、属性名, 通过getNodeValue()获取属性值、元素值,通过getChildNodes()获取子节点们,通过item(i)获取第i个属性或者第i个子节点。

DOM解析代码实例

构造Document对象:

   /**
     * 构建Document对象
     * @param xmlPath
     * @return
     */
    private static Document buildDocument(String xmlPath){
        try {
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(xmlPath);
            return documentBuilder.parse(inputStream);
        } catch (Exception e) {
            System.out.println(e);
        }
        return null;
    }

遍历DOM对象

Document:   XML文档对象,由解析器获取
            NodeList:   节点数组
            Node:       节点(包括element、#text)
            Element:    元素,可用于获取属性参数

DOM解析完整代码示例

package com.demo;
​
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
​
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
​
public class DomDemo {
​
    public static void main(String[] args) {
​
        try {
            find();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
​
    private static User find() throws Exception {
        Document document = buildDocument("users.xml");
        NodeList list = document.getElementsByTagName("user");
        for (int i = 0; i < list.getLength(); i++) {
            Element element = (Element) list.item(i);
​
            User student = new User();
            student.setUserId(Long.parseLong(element.getAttribute("userId")));
            student.setIdCard(element.getAttribute("idcard"));
            student.setName(element.getElementsByTagName("name").item(0).getTextContent());
            student.setAddress(element.getElementsByTagName("address").item(0).getTextContent());
            student.setAge(element.getElementsByTagName("age").item(0).getTextContent());
            System.out.println(student);
        }
        return null;
    }
​
    /**
     * 构建Document对象
     * @param xmlPath
     * @return
     */
    private static Document buildDocument(String xmlPath){
        try {
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(xmlPath);
            return documentBuilder.parse(inputStream);
        } catch (Exception e) {
            System.out.println(e);
        }
        return null;
    }
​
}
​

SAX(Simple API for XML)解析

流模型中的"推"模型分析方式。通过事件驱动,每发现一个节点就引发一个事件,事件推给事件处理器,通过回调方法完成解析工作,解析XML文档的逻辑需要应用程序完成

原理

通过parse(file,listener)函数用一个listener对xml文件进行查找,按顺序读取文档,遍历每个标签,当发现目标标签时,读取标签的属性、结点值等信息并返回。

【优势】 ①无需将整个xml文档载入内存,因此消耗内存少。 ②只在读取数据时检查数据,不需要保存在内存中。 ③可以在某个条件得到满足时停止解析,不必解析整个文档。 ④效率和性能较高,能解析大于系统内存的文档。 【缺点】 ①不能随机的访问xml中的节点。 ②单向导航,无法定位文档层次,很难同时访问同一文档的不同部分数据,不支持XPath。 ③不能修改文档。

SAX解析详解

操作步骤:

1:创建解析工厂:SAXParserFactory factory = SAXParserFactory.newInstance();

2:由工厂创建解析器:SAXParser parser = factory.newSAXParser();

3:通过解析器的parse()方法,对指定xml文档以指定handler之类进行解析查询:parser.parse(xmlFile, new MySaxListener());

我们要继承DefaultHandler类,定义相应的查询操作类:

1:重写父类中的文档开始方法、文档结束方法,定义开始、结束遍历xml文档时的操作:

void startDocument() 
          接收文档开始的通知。 
​
 void endDocument() 
          接收文档结束的通知。

2:重写父类的标签开始方法、标签结束方法,定义遍历到一个开始、结束标签时的操作:

void startElement(String uri, String localName, String qName, Attributes attributes) //参数qName是标签名、attributes是属性列表
          接收元素开始的通知。 
​
void endElement(String uri, String localName, String qName) 
          接收元素结束的通知。

3:重写**characters**(char[] ch, int start, int length)方法:

   // 对事件发生时,元素的字符怎么处理  
    public void characters(char[] ch, int start, int length) throws SAXException {
        //参数ch是当上述4中事件随便一个发生时,对应的元素的值,值在ch中start开始,length长。从头到尾遍历整个xml文档时,每个标签的值依次被存入ch中。
​
 }

总结:

也就是说,通过SAX解析xml文档是没有dom对象出现的,所以不会有node,不会有getNodeName()、getNodeValue()获取结点名、值。 总结:SAX解析XML文档的结点名是通过事件函数的参数qName获取的,属性是通过参数attributes的getValue("属性名")获取的, 结点值是通过当前事件函数发生时,characters(char[] ch, int start, int length)方法中的内容获取的。

【事件处理器类型】 ①访问XML DTD:DTDHandler ②低级访问解析错误:ErrorHandler ③访问文档内容:ContextHandler 【DefaultHandler类】 SAX事件处理程序的默认基类,实现了DTDHandler、ErrorHandler、ContextHandler和EntityResolver接口,通常 做法是,继承该基类,重写需要的方法,如startDocument() 注:关于遍历 ①深度优先遍历(Depthi-First Traserval) ②广度优先遍历(Width-First Traserval)

SAX解析详解

创建SAX解析器

SAXParserFactory saxf = SAXParserFactory.newInstance();
 SAXParser sax = saxf.newSAXParser();

JDOM解析

JDOM方法是根据DOM方法的众多繁琐操作进行包装得到的,上面我们看到,DOM方法解析XML文档其实是很繁琐的,而且很混乱,标签、属性、换行空格都当作结点类型来处理。JDOM方法定义了一系列通俗、好记的方法来解析XML,方法的底层封装了一系列DOM操作,但是我们不必亲自去进行这些繁琐的工作了。

优点:

a、DOM方式的优点:查找方便,可以修改 缺点 a、DOM方式的缺点:装载整个文档,对内存容量要求高

在JDOM中,同一了根节点、普通结点、属性等全为Element类型。

JDOM解析详解

操作步骤:

1:创建一个SAXbuilder:SAXBuilder builder = new SAXBuilder();

2:创建文件输入流打开xml文件:InputStream in = new FileInputStream("XXX.xml");

3:通过builder,从输入流读取xml文件创建dom对象:Document dom = builder.build(in);

4:获取根节点:Element root=dom.getRootElement();

5:获取子节点列表:List<Element> childNodes = node.getChildren();

6:遍历子节点列表,获取第i个结点:Element node = childNodes.get(i);

7:读取结点信息:

1)结点属性值:node.getAttributeValue("属性名");

2)结点名:node.getName();

3)结点值:node.getValue();

4)子结点文本值:node.getChildText("子结点名");

Dom4j解析

Dom4j是目前最流行、最好用的XML解析工具,解析XML的速度最快。

Dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的。

Mave依赖

     <dependency>
          <groupId>dom4j</groupId>
          <artifactId>dom4j</artifactId>
          <version>1.6.1</version>
      </dependency>

DOM4j解析详解

操作步骤:

1:创建SAXReader:SAXReader reader = new SAXReader();

2:创建文件输入流打开xml文件:InputStream in = new FileInputStream("XXX.xml");

3:通过reader和输入流读取xml文件到内存创建Document对象:Document dom = reader.read(in);

4:获取根节点:Element root=dom.getRootElement();

5:获取子节点列表:List<Element> childNodes = root.elements();

6:遍历子节点:Element node = childNodes.get(i);

7:读取结点信息:

1)结点属性值:node.attributeValue("属性名");

2)结点名:node.getName();

3)结点值:node.getValue();

4)子结点文本值:node.elementText("子结点名")

实例代码

package com.demo;
​
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
​
import java.io.InputStream;
import java.util.List;
​
public class Dom4jDemo {
    public static void main(String[] args) throws DocumentException {
        SAXReader reader = new SAXReader();
        InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("users.xml");
        Document document = reader.read(inputStream);
        Element rootElement = document.getRootElement();
        List<Element> elements = rootElement.elements("user");
        for (Element element :
                elements) {
            User user = new User();
            user.setUserId(Long.parseLong(element.attribute("userId").getValue()));
            user.setIdCard(element.attribute("idcard").getValue());
            user.setName(element.elementText("name"));
            user.setAddress(element.elementText("address"));
            user.setAge(element.elementText("age"));
            System.out.println(user);
        }
    }
}
​

总结:

1)DOM、JDOM、DOM4j都是把xml文档读取到内存中,生成dom对象进行遍历的;

DOM是Java原生的,所以比较繁琐;

JDOM是对DOM操作的封装,更加通俗、易记,操作也快了一点;

DOM4j解析xml的函数上与JDOM差不多,只不过有几个相同功能的函数名字不同而已,过程都是一样的;但由于底层使用了Xpath等方法加快了索引,所以检索性能更快。

2)SAX是基于事件驱动的,查询事件监听器继承自DefaultHandler,定义了检索xml过程中遇到开始标签、结束标签时执行的事件函数,从而查找需要的信息并返回而不是把整个文档都加载进来

比较

1)DOM4J性能最好,连Sun的JAXM也在用DOM4J。目前许多开源项目中大量采用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文件。如果不考虑可移植性,那就采用DOM4J.

2)JDOM和DOM在性能测试时表现不佳,在测试10M文档时内存溢出。在小文档情况下还值得考虑使用DOM和JDOM。虽然JDOM的开发者已经说明他们期望在正式发行版前专注性能问题,但是从性能观点来看,它确实没有值得推荐之处。另外,DOM仍是一个非常好的选择。DOM实现广泛应用于多种编程语言。它还是许多其它与XML相关的标准的基础,因为它正式获得W3C推荐(与基于非标准的Java模型相对),所以在某些类型的项目中可能也需要它(如在JavaScript中使用DOM)。

3)SAX表现较好,这要依赖于它特定的解析方式-事件驱动。一个SAX检测即将到来的XML流,但并没有载入到内存.还有就是只能读取不能修改xml(当然当XML流被读入时,会有部分文档暂时隐藏在内存中)。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!