XML 解析
1. 解析概述
当将数据存储在XML后,我们就希望通过程序获得XML的内容。如果我们使用Java基础所学习的IO知 识是可以完成的,不过你需要非常繁琐的操作才可以完成,且开发中会遇到不同问题(只读、读写)。 人们为不同问题提供不同的解析方式,并提交对应的解析器,方便开发人员操作XML。
2.XML解析方式
开发中比较常见的解析方式有两种,如下:
2.1 DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象。
- 优点:元素与元素之间保留结构关系,故可以进行增删改查操作。
- 缺点:XML文档过大,可能出现内存溢出显现。
2.2 SAX:是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。并以事件驱动的方 式进行具体解析,每执行一行,都将触发对应的事件。(了解)
- 优点:占用内存少 处理速度快,可以处理大文件
- 缺点:只能读,逐行后将释放资源。
3. XML常见的解析器
解析器:就是根据不同的解析方式提供的具体实现。有的解析器操作过于繁琐,为了方便开发人员, 有提供易于操作的解析开发包
- JAXP:sun公司提供的解析器,支持DOM和SAX两种思想
- DOM4J:一款非常优秀的解析器 , Dom4j是一个易用的、开源的库,用于XML,XPath和XSLT。它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP。
- Jsoup:jsoup 是一款Java 的HTML解析器 ,也可以解析XML
- PULL:Android内置的XML解析方式,类似SAX。
4. dom4j 的使用
4.1 导入JAR包
4.2 API介绍
使用核心类SaxReader加载xml文档获得Document,通过Document 对象获得文档的根元素,然后就可以操作了
常用API如下:
- SaxReader对象
read(…) 加载执行xml文档
- Document对象
getRootElement() 获得根元素
- Element对象
elements(…) 获得指定名称的所有子元素。可以不指定名称
element(…) 获得指定名称的第一个子元素。可以不指定名称
getName() 获得当前元素的元素名
attributeValue(…) 获得指定属性名的属性值
elementText(…) 获得指定名称子元素的文本值
getText() 获得当前元素的文本内容
5. 准备xml文件
编写user.xsd schema约束,代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://www.lagou.com/xml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.lagou.com/xml"
elementFormDefault="qualified">
<xsd:element name="users" type="usersType"/>
<xsd:complexType name="usersType">
<xsd:sequence>
<xsd:element name="user" type="userType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="userType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="age" type="ageType" />
<xsd:element name="hobby" type="hobbyType" />
</xsd:sequence>
<xsd:attribute name="id" type="numberType" use="required"/>
</xsd:complexType>
<xsd:simpleType name="ageType">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="100"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="hobbyType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="抽烟"/>
<xsd:enumeration value="喝酒"/>
<xsd:enumeration value="烫头"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="numberType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
编写user.xml 引入约束,代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<users
xmlns="http://www.lagou.com/xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.lagou.com/xml user.xsd"
>
<user id="1">
<name>张百万</name>
<age>20</age>
<hobby>抽烟</hobby>
</user>
<user id="2">
<name>于谦</name>
<age>50</age>
<hobby>喝酒</hobby>
</user>
<user id="3">
<name>刘能</name>
<age>40</age>
<hobby>烫头</hobby>
</user>
</users>
6. 读取XML
public class TestDOM4j {
//获取XML文件中的 所有的元素名称(标签) @Test
public void test1() throws DocumentException {
//1.获取XML解析对象
SAXReader reader = new SAXReader();
//2.解析XML 获取 文档对象 document Document document =
reader.read("H:\\jdbc_work\\xml_task03\\src\\com\\lagou\\xml03\\user.xml");
//3.获取根元素
Element rootElement = document.getRootElement();
//获取根元素名称System.out.println(rootElement.getName());
//获取 根元素下的标签
List<Element> elements = rootElement.elements(); for (Element element : elements) {
System.out.println("根标签下的子节点: " + element.getName());
List<Element> eList = element.elements(); for (Element e : eList) {
System.out.println("user标签下的子节点" + e.getName());
}
break;
}
}
/**
* 获取具体的节点内容 获取张百万的所有信息
*/ @Test
public void test2() throws DocumentException {
//1.创建XML文档解析对象
SAXReader sr = new SAXReader();
//2.读取XML获取到document对象
Document document = sr.read("src\\com\\lagou\\xml02\\user.xml");
//3.获取根节点
Element rootElement = document.getRootElement();
//4.得到当前节点的 所有子节点
List<Element> elements = rootElement.elements();
//5.获取第一个子节点
Element user = elements.get(0);
//6.获取所有信息
String id = user.attributeValue("id"); String name = user.elementText("name"); String age = user.elementText("age");
//使用getText获取当前元素的文本内容
String hobby = user.element("hobby").getText();
//打印
System.out.println(id+" " + name +" " + age +" " + hobby);
}
7. xpath方式读取xml
7.1 xpath介绍
XPath 是一门在 XML 文档中查找信息的语言。 可以是使用xpath查找xml中的内容。
XPath 的好处
由于DOM4J在解析XML时只能一层一层解析,所以当XML文件层数过多时使用会很不方便,结合
XPATH就可以直接获取到某个元素
需要再导入 jaxen-1.1-beta-6.jar
7.2 XPath基本语法介绍
使用dom4j支持xpath的操作的几种主要形式
语法 | 说明 |
/AAA/DDD/BBB | 表示一层一层的,AAA下面 DDD下面的BBB |
//BBB | 表示和这个名称相同,表示只要名称是BBB,都得到 |
//* | 所有元素 |
BBB[1] , BBB[last()] | 第一种表示第一个BBB元素, 第二种表示最后一个BBB元素 |
//BBB[@id] | 表示只要BBB元素上面有id属性,都得到 |
//BBB[@id='b1'] | 表示元素名称是BBB,在BBB上面有id属性,并且id的属性值是b1 |
7.3 API介绍
常用方法:
- selectSingleNode(query): 查找和 XPath 查询匹配的一个节点。
参数是Xpath 查询串。
- selectNodes(query): 得到的是xml根节点下的所有满足 xpath 的节点;
参数是Xpath 查询串。
- Node: 节点对象
7.4 Xpath读取XML
1)数据准备book.xml 代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<bookstore>
<book id="book1">
<name>金瓶梅</name>
<author>金圣叹</author>
<price>99</price>
</book>
<book id="book2">
<name>红楼梦</name>
<author>曹雪芹</author>
<price>69</price>
</book>
<book id="book3">
<name>Java编程思想</name>
<author>埃克尔</author>
<price>59</price>
</book>
</bookstore>
2)使用Xpath语法解析book.xml 代码如下:
package com.lagou.xml04;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.Test;
import java.util.List;
public class TestXPath {
/*
* 使用selectSingleNode() 方法 查询自定的节点信息
*
* */
@Test
public void test1() throws DocumentException {
//1.创建XML解析对象
SAXReader reader = new SAXReader();
//2.解析XML 获取 文档对象
Document document = reader.read("H:\\jdbc_work\\xml_task03\\src\\com\\lagou\\xml04\\book.xml");
//3.通过selectSingleNode() 方法获取 name节点
Node node1 = document.selectSingleNode("/bookstore/book/name");
System.out.println("节点的名称: " + node1.getName());
System.out.println("书名: " + node1.getText());
//4.获取第二本书的书名
Node node2 = document.selectSingleNode("/bookstore/book[3]/name");
System.out.println("书名: " + node2.getText());
}
/*
* 使用 selectSIngleNode() 方法获取 属性值 或者 通过属性值获取到节点信息
*
* */
@Test
public void test2() throws DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read("H:\\jdbc_work\\xml_task03\\src\\com\\lagou\\xml04\\book.xml");
//1.获取第一个booke节点中的 id属性的值
Node node1 = document.selectSingleNode("/bookstore/book/attribute::id");
System.out.println("第一个book的id属性值: " + node1.getText() );
//2.获取最后一个book节点的 id属性值
Node node2 = document.selectSingleNode("/bookstore/book[last()]/attribute::id");
System.out.println("最后一个book节点中的属性值: " + node2.getText());
//3.通过id的值 获取book2节点 中的书名
Node node3 = document.selectSingleNode("/bookstore/book[@id='book2']");
String name = node3.selectSingleNode("name").getText();
System.out.println("id为book2的 节点的书名是: " + name);
}
/*
* 使用selectNodes() 获取所有指定名称 的节点
*
* */
@Test
public void test3() throws DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read("H:\\jdbc_work\\xml_task03\\src\\com\\lagou\\xml04\\book.xml");
//1.查询所有的节点
List<Node> list = document.selectNodes("//*");
for (Node node : list) {
System.out.println("节点名: " + node.getName());
}
//2.获取所有的书名
List<Node> list1 = document.selectNodes("//name");
for (Node node : list1) {
System.out.println("书名: " + node.getText());
}
//3.获取 id值为 book1 的节点中的所有内容
List<Node> list2 = document.selectNodes("/bookstore/book[@id='book1']//*");
for (Node node : list2) {
System.out.println(node.getName() + " = " + node.getText());
}
}
}
节选自拉钩教育JAVA系列教程