DOM、DOM4J、SAX和XPath解析xml文件

1,222 阅读6分钟

由于解析spring等相关源码经常要用到xml解析技术,就带大家来复习一下xml技术

一、XML文件

1.1 什么是xml文件

xml是可拓展标记语言,(Extensible Markup Language)就是开发者在符合xml命名规则的基础之上,可以根据自己的需求定义自己的标签;

1.2 xml文件的作用

主要是用来存储数据

1.3 解析xml文件的方法: DOM、DOM4J、SAX

二、DOM4J解析xml文件

2.1 导入Dom4J依赖

2.2 Dom4j的常用对象

2.2.1 SAXReader:读取xml文件到Document树结构文件对象

2.2.2 Document:是一个xml文档对象树,类比Html文档对象

2.2.3 Element:元素节点。通过Document对象可以查找当个元素

2.3 Dom4j解析步骤

2.3.1 创建解析器 SAXReader reader = new SAXReader(); 2.3.2 Document对象:通过解析器read方法获取 Document document = saxReader.read("students.xml"); 2.3.3 获取xml根节点 Element root = document.getRootElement(); 2.3.4 遍历解析子节点

2.4 示例一:使用Dom4j解析students.xml文件

students.xml

<?xml version="1.0" encoding="UTF-8" ?>
<students>
    <student>
        <name>哈哈</name>
        <college>java</college>
    </student>
    <student>
        <name>搜索</name>
        <college>c++</college>
    </student>
    <student>
        <name>哈哈</name>
        <college>app</college>
    </student>
</students>

引入依赖

<dependency>
    <groupId>org.dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>2.1.3</version>
</dependency>

Dom4jTest.java

package com.qinghong;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.util.Iterator;

public class Dom4jTest {
    public static void main(String[] args) {
        // 创建解析器
        SAXReader reader = new SAXReader();
        // 通过解析器的read将配置文件读取到内存中 生成一个Document[org.dom4j]对象树
        try {
            Document document = reader.read("students.xml");
            // 获取根节点
            Element root = document.getRootElement();
            // 遍历
            for (Iterator<Element> rootIter = root.elementIterator();rootIter.hasNext();){
                Element element = rootIter.next();
                for (Iterator<Element> innerIter = element.elementIterator();innerIter.hasNext();){
                    Element next = innerIter.next();
                    String innerValue = next.getStringValue();
                    System.out.println(innerValue);
                }
                System.out.println("------------");
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }
}

得到结果

xml1.png

三、Sax解析xml文件

3.1 SAX方式:事件驱动,边读边写

3.1.1 执行过程如下图 3.1.2 优点:无需将整个文档加载到内存中,所以内存消耗少,适合解析特别大的xml文件 3.1.3 SAX解析四步曲: (1) 创建解析工厂:通过newInstance()方法获取 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); (2) 创建解析器 SAXParser saxParser = saxParserFactory.newSAXParser(); (3) 调用 parser方法 (4) 原理图如下:

xml2.png 代码实现:

MySAXParser.java

package com.qinghong;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

public class MySAXParser {
    public static void main(String[] args) {
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        try {
            SAXParser saxParser = saxParserFactory.newSAXParser();
            saxParser.parse("students.xml",new MyDefaultHandler());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyDefaultHandler extends DefaultHandler{
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        System.out.println("<" + qName + ">");
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        System.out.println("</" + qName + ">");
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        System.out.println(new String(ch,start,length));
    }
}

四、使用Dom4j的xPath解析xml文件

4.1 XPath语法

教程:www.w3school.com.cn/xpath/index…

XPath 使用路径表达式来选取 XML 文档中的节点或节点集。节点是通过沿着路径 (path) 或者步 (steps) 来选取的。

下面列出了最有用的路径表达式:

选取节点

表达式描述
nodename选取此节点的所有子节点。
/从根节点选取。
//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
.选取当前节点。
..选取当前节点的父节点。
@选取属性。

谓语(Predicates)

谓语用来查找某个特定的节点或者包含某个指定的值的节点。

谓语被嵌在方括号中。

实例

在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:

路径表达式结果
/bookstore/book[1]选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()]选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1]选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()<3]选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang]选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang='eng']选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00]选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]/title选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

选取未知节点

XPath 通配符可用来选取未知的 XML 元素。

通配符描述
*匹配任何元素节点。
@*匹配任何属性节点。
node()匹配任何类型的节点。

实例

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式结果
/bookstore/*选取 bookstore 元素的所有子元素。
//*选取文档中的所有元素。
//title[@*]选取所有带有属性的 title 元素。

选取若干路径

通过在路径表达式中使用“|”运算符,您可以选取若干个路径。

实例

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式结果
//book/title//book/price选取 book 元素的所有 title 和 price 元素。
//title//price选取文档中的所有 title 和 price 元素。
/bookstore/book/title//price选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。

4.2 实例:获取xml文件的配置信息

准备工作

<?xml version="1.0" encoding="ISO-8859-1"?>

<bookstore>

<book>
  <title lang="eng">Harry Potter</title>
  <price>29.99</price>
</book>

<book>
  <title lang="eng">Learning XML</title>
  <price>39.95</price>
</book>

</bookstore>

SysConfigParser.java

package com.qinghong;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class SysConfigParser {
    public static void main(String[] args) throws DocumentException {
        // 构建解析器
        SAXReader saxReader = new SAXReader();
        // 通过解析器的read方法将配置文件读取到内存中,生成一个Document[dom4j]对象树
        Document document = saxReader.read("book.xml");
        // title节点元素的xpath路径:/bookstore/book/title
        // title节点元素的xpath路径:bookstore//title
        // title节点元素的xpath路径://title
        Element title = (Element) document.selectSingleNode("//title");
        String stringValue = title.getStringValue();
        System.out.println(stringValue);

        // 获取title节点元素对象的lang属性
        Attribute lang = title.attribute("lang");
        // 获取lang属性的值
        String value = lang.getStringValue();

        // 直接获取title节点元素对象的lang属性名字
        String s = title.attributeValue("lang");

    }
}

五、使用XPath对象解析xml文件

bookstore.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
    1.获取bookstore节点下book属性category值为web下的第二个title节点的文本内容
    bookstore -> book[@category='web'][2] -> title
    xpath路径: /bookstore/book[@category='web'][2]/title/text()
    2.获取bookstore节点下book属性category值为web的title属性为en的节点内容
    bookstore -> book[@category='web'] -> title[@lang = 'en']
    xpath路径: /bookstore/book[@category='web']/title[@lang = 'en']/text()
    3.获取bookstore节点下book属性category值为cooking的title的lang属性的值
    bookstore -> book[@category='cooking'] -> title -> @lang
     xpath路径: /bookstore/book[@category='cooking']/@lang
    4.获取bookstore节点下所有book的节点集合
    /bookstore/book
-->
<bookstore>
    <book category="children">
        <title lang="eng">Harry Potter</title>
        <price>29.99</price>
        <year>2005</year>
    </book>
    <book category="web">
        <title lang="eng">Learning XML</title>
        <price>39.95</price>
        <year>2003</year>
    </book>
    <book category="cooking">
        <title lang="eng">Everyday Italian</title>
        <price>39.95</price>
        <year>2003</year>
    </book>
    <book category="web">
        <title lang="uk">XQuery Kick Start</title>
        <price>39.95</price>
        <year>2003</year>
    </book>
</bookstore>

实例:

package com.qinghong;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;

public class MyXPathTest {
    public static void main(String[] args){
        try {
            // 创建解析工厂
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            // 创建解析器
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            // 通过解析器读取配置文件,生成一个import org.w3c.dom.Document包下的
            Document document = documentBuilder.parse("bookstore.xml");

            // 创建XPath对象
            XPath xPath = XPathFactory.newInstance().newXPath();

            // bookstore -> book[@category='web'][2] -> title
            // xpath路径: /bookstore/book[@category='web'][2]/title/text()

            String titleXpath = "/bookstore/book[@category='web'][2]/title/text()";
            String titleValue = (String) xPath.evaluate(titleXpath, document, XPathConstants.STRING);
            System.out.println(titleValue);

            // 2.获取bookstore节点下book属性category值为web的title属性为en的节点内容
            // bookstore -> book[@category='web'] -> title[@lang = 'en']
            // xpath路径: /bookstore/book[@category='web']/title[@lang = 'en']/text()
            String titleXpath2 = "/bookstore/book[@category='web']/title[@lang = 'en']/text()";
            String titleValue2 = (String) xPath.evaluate(titleXpath2, document, XPathConstants.STRING);
            System.out.println(titleValue2);

            // 3.获取bookstore节点下book属性category值为cooking的title的lang属性的值
            // bookstore -> book[@category='cooking'] -> title -> @lang
            // xpath路径: /bookstore/book[@category='cooking']/@lang
            String titleLangAttrXpath = "/bookstore/book[@category='cooking']/@lang";
            String titleLangAttrValue = (String) xPath.evaluate(titleLangAttrXpath, document, XPathConstants.STRING);
            System.out.println(titleLangAttrValue);

            // 4.获取bookstore节点下所有book的节点集合
            // /bookstore/book
            NodeList nodeList = (NodeList) xPath.evaluate("/bookstore/book", document, XPathConstants.NODESET);
            // 开始遍历
            for (int i = 0; i < nodeList.getLength(); i++) {
                Element item = (Element) nodeList.item(i);
                String title = (String) xPath.evaluate("title", item, XPathConstants.STRING);
                System.out.println(title);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}