使用Java操作xml文档
DOM文档对象模型
DOM定义了访问和操作XML文档的标准方法,DOM把XML文档作文树结构来查看,能够通过DOM树来读写所有元素。
Dom4j
https://dom4j.github.io/
Dom4j是一个易用的、开源的库,用于解析XML。它应用于Java平台,具有性能优异、功能强大和极易使用的特点。
Dom4j将XML视为Document对象。
XML标签被Dom4j定义为Element对象。
xml数据hr.xml
<?xml version="1.0" encoding="UTF-8"?>
<hr xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="hr.xsd">
<employee no="3309">
<name>x1</name>
<age>20</age>
<salary>4000</salary>
<department>
<dname>会计部</dname>
<address>XX大厦-B102</address>
</department>
</employee>
<employee no="3109">
<name>x2</name>
<age>20</age>
<salary>4000</salary>
<department>
<dname>会计部</dname>
<address>XXX</address>
</department>
</employee>
<employee no="4233">
<name>x3</name>
<age>22</age>
<salary>3622</salary>
<department>
<dname>会计部</dname>
<address>xx大楼-710</address>
</department>
</employee>
</hr>
hr.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<element name="hr">
<!-- complexType标签含义是复杂节点,包含子节点时必须使用这个标签-->
<complexType>
<!-- sequence标签表示每个标签必须严格按顺序编写-->
<sequence>
<!-- element节点最少出现一次,最多出现9999次 -->
<element name="employee" minOccurs="1" maxOccurs="9999">
<complexType>
<sequence>
<element name="name" type="string"></element>
<element name="age">
<!-- 限制age的取值范围18-60 -->
<simpleType>
<restriction base="integer">
<minInclusive value="18"></minInclusive>
<maxInclusive value="60"></maxInclusive>
</restriction>
</simpleType>
</element>
<element name="salary" type="integer"></element>
<element name="department">
<complexType>
<sequence>
<element name="dname" type="string"></element>
<element name="address" type="string"></element>
</sequence>
</complexType>
</element>
</sequence>
<!-- use=required表示no属性在任何employee中都是必须的-->
<attribute name="no" type="string" use="required"></attribute>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
读取Xml数据
package com.study.dom4j;
import java.io.File;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class HrReader {
public void readXml() {
File file = new File("src/hr.xml");
SAXReader reader = new SAXReader();
try {
Document document = reader.read(file);
//获取文档的根节点,即hr标签
Element root = document.getRootElement();
//elements方法用于获取指定的标签集合
List<Element> employees = root.elements("employee");
for(Element employee:employees) {
//element方法用于获取唯一的子节点对象
Element name = employee.element("name");
//getText方法用于获取标签文本
String empName = name.getText();
System.out.println(empName);
//方法2 elementText直接获取传入的标签参数文本
System.out.println(employee.elementText("age"));
System.out.println(employee.elementText("salary"));
Element department = employee.element("department");
System.out.println(department.elementText("dname"));
System.out.println(department.elementText("address"));
//获取属性
Attribute att = employee.attribute("no");
System.out.println(att.getText());
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
HrReader reader = new HrReader();
reader.readXml();
}
}
写入Xml数据
在写入数据的时候,不会校验dtd约束
package com.study.dom4j;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class HrWriter {
public void writeXml() {
File file = new File("src/hr.xml");
SAXReader reader = new SAXReader();
try {
Document document = reader.read(file);
Element root = document.getRootElement();
Element employee = root.addElement("employee");
employee.addAttribute("no", "4233");
//方法一:创建标签添加到标签
Element name = employee.addElement("name");
name.setText("x3");
//方法二:直接添加到标签中
employee.addElement("age").setText("22");
employee.addElement("salary").setText("3622");
Element department = employee.addElement("department");
department.addElement("dname").setText("会计部");
department.addElement("address").setText("xx大楼-710");
//结构内容定义好后写入文件,因为写入文件也需要异常检查,只需要将DocumentException的级别提示到Exception即可
Writer writer = new OutputStreamWriter(new FileOutputStream(file),"UTF-8");
document.write(writer);
writer.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
public static void main(String[] args) {
HrWriter writer = new HrWriter();
writer.writeXml();
}
}
XPath路径表达式
XPath路径表达式是XML文档中查找数据的语言。
掌握XPath可以极大的提高在提取数据时的开发效率。
学习XPath本质就是掌握各种形式表达式的使用技巧。
最常用的基本表达式
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 从根节点选取。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点。 |
… | 选取当前节点的父节点。 |
@ | 选取属性。 |
XPath基本表达式案例
路径表达式 | 结果 |
---|---|
bookstore | 选取bookstore元素的所有子节点。 |
/bookstore | 选取根元素bookstore。注释:假如路径起始于正斜杠(/),则此路径始终代表到某元素的绝对路径! |
bookstore/book | 选取所有book子元素,而不管它们在文档中的位置。 |
//book | 选取所有book子元素,而不管它们在文档中的位置。 |
bookstore//book | 选择属于bookstore元素的后代的所有book元素,而不管它们位于bookstore之下的什么位置。 |
//@lang | 选取名为lang 的所有属性。 |
XPath谓语表达式
路径表达式 | 结果 |
---|---|
/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。 |
代码案例
package com.study.dom4j;
import java.io.File;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
public class XPathTestor {
public void xpath(String xpathExp) {
File file = new File("src/hr.xml");
SAXReader reader = new SAXReader();
try {
Document document = reader.read(file);
//返回xpathExp查询到的节点
List<Node> nodes = document.selectNodes(xpathExp);
for (Node node : nodes) {
Element emp = (Element) node;
System.out.println(emp.attributeValue("no"));
System.out.println(emp.elementText("name"));
System.out.println(emp.elementText("age"));
System.out.println(emp.elementText("salary"));
Element department = emp.element("department");
System.out.println(department.elementText("dname"));
System.out.println(department.elementText("address"));
System.out.println("==================");
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
XPathTestor testor = new XPathTestor();
// 单斜杠从根节点开始,双斜杠表示从任意节点开始匹配
// testor.xpath("/hr/employee");
// testor.xpath("//employee");
// 指定条件筛选
// testor.xpath("//employee[salary<4000]");
// testor.xpath("//employee[name='x1']");
// 根据属性筛选
// testor.xpath("//employee[@no=3309]");
// 第一个元素
// testor.xpath("//employee[1]");
// 最后一个元素
// testor.xpath("//employee[last()]");
// 按照范围筛选(前6个)
// testor.xpath("//employee[position()<6]");
// 组合表达式
testor.xpath("//employee[3] | //employee[1]");
}
}