up:: XML使用Dom4j写追加XML文档

问题引入:把工资大于3000的员工提取出来;或者,编号为3310的员工信息提出来;难道要编写程序挨个遍历,然后提取?显然不可取,工作量太大;

XML有专门的查询工具:XPath;


一:XPath简介

XPath:是XML的查询语言,可以极大简化XML的查询和提取的过程;

1.XPath两种最常见的表达式:基本表达式;谓语表达式;

(1)XPath基本表达式


(2)XPath谓语表达式:在基本表达式的基础上,增加了额外的约束条件


2.在使用Dom4j,利用XPath查询时候,必须要先下载Jaxen的jar包;

发现,无法访问http://jaxen.codehaus.org/

解决办法:可以访问https://maven.aliyun.com/mvn/search;通过阿里提供的代码仓库找到需要的jar包:


二:XPath示例程序

1.准备的XML:

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- 人力资源管理系统 --><!--xmlns:xsi的意思是告诉XML文档,我们的约束是使用Schema;xsi:noNamespaceSchemaLocation:指向xsd文件 -->
    <hr xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:noNamespaceSchemaLocation="hr-schema.xsd">
    	<employee no="3301">   <!-- 标签和属性尽量起的有意义,做到见名知意 -->
    		<name>李刚</name>
    		<age>31</age>
    		<salary>4000</salary>
    		<department>    <!-- 标签可以嵌套 -->
    			<dName>会计</dName>
    			<dAddress>4楼103室</dAddress>
    		</department>
    	</employee>
    	<employee no="3302">
    		<name>李四</name>
    		<age>29</age>
    		<salary>5000</salary>
    		<department>
    			<dName>工程部门</dName>
    			<dAddress>4楼105室</dAddress>
    		</department>
    	</employee>
    	<employee no="3303">
    		<name>王红</name>
    		<age>35</age>
    		<salary>3800</salary>
    		<department>
    			<dName>行政部门</dName>
    			<dAddress>3楼301室</dAddress>
    		</department>
    	</employee>
    	<employee no="3304">
    		<name>王华</name>
    		<age>28</age>
    		<salary>4300</salary>
    		<department>
    			<dName>行政部门</dName>
    			<dAddress>3楼301室</dAddress>
    		</department>
    	</employee>
    	<employee no="3305">
    		<name>刘铁</name>
    		<age>27</age>
    		<salary>3300</salary>
    		<department>
    			<dName>行政部门</dName>
    			<dAddress>3楼301室</dAddress>
    		</department>
    	</employee>
    </hr>

2.查询的基本程序架构:

下面的核心是:

(1)List<Node> nodes = document.selectNodes(xpathExp); 核心查询方法,返回查询到的所有满足条件的Node列表; xpathExp就是XPath表达式

(2)emp.attributeValue(“no”):查询属性的方法;

(3)emp.elementText(“name”):查询标签值的方法;

    public class XpathTest {
    	public void xpath(String xpathExp) {
    		String file = "e:/eclipse-workspace/xml/src/hr-schema.xml";
    		//(1) SAXReader是读取XML文件的核心类,用于将XML解析后以“树”的形式保存在内存中。
    		SAXReader reader = new SAXReader();
    		try {
    			// (2) SAXReader类的主要方法时read()方法,该方法返回一个Document对象;
    			Document document = reader.read(file);
    			// 返回的是Node的集合;为什么说是Node而不是Element?因为,XPath表达式不仅可以查询标签(Element),还可以查询属性(Attribute),Node是Element和Attribute的父类
    			List<Node> nodes = document.selectNodes(xpathExp);
    			for(Node node:nodes) {  // 遍历查询到的满足条件的节点(Node)
    				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"));
    				System.out.println("==========================");
    			}
    		} catch (DocumentException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
 
    	public static void main(String[] args) {
    		XpathTest testor = new XpathTest();
    //		testor.xpath("/hr/employee");
    //		testor.xpath("//employee");
    //		testor.xpath("//employee[salary>=4000]");
    //		testor.xpath("//employee[name='李四']");  // 用单引号
    //		testor.xpath("//employee[@no=3304]");
    //		testor.xpath("//employee[1]");
    //		testor.xpath("//employee[position()<4]");
    		testor.xpath("//employee[2] | //employee[4] | //employee[5]");  // 中间的竖杠的意思是把前后两个表达式的结果进行合并
    	}
 
    }

3.在上面基本程序架构中,使用不同的XPath表达式,查询演示

举例子: 不同的XPath表达式,作为 selectNodes() 方法的参数,就会得到满足XPath表达式条件的一个集合 :List<Node> nodes = document.selectNodes(xpathExp);

(1)查询所有根节点(<hr>元素)下所有直接的子<employeegt;元素:“/hr/employee”

“/hr/employee”:会按照原XML的顺序,得到 <employeegt;不会乱顺序,这个不会乱顺序是指,只能获取<hrgt;的直接子标签的<employeegt;标签;

效果:全部打出来了

**(2)查询XML中所有的 <employeegt;元素:

“//employee”** 和(1)结果相同,所有 <employeegt;全部打出来了;“//employee”:不管<employeegt;这个标签在哪儿,也不管其是不是<hrgt;的直接子标签,只要是XML中<emppoyeegt;标签都获取

效果:

(3)获取所有“ <salarygt;元素值大于等于4000”的<employeegt;元素:“//employee[salary>=4000]”

统计所有工资小于4000的工人,salary是employee的子节点;下面 利用[ ]添加了查询的筛选条件,这比我们在Java中写代码筛选高效的多;

结果:

(4)查询, <namegt;元素值为“李四”的,<employeegt;元素:“//employee[name=‘李四’]”

提取“李四”的信息(即提取某一项信息), 利用[ ]添加了查询的筛选条件;

结果:

(5)查询,属性等于某值的,所有 <employeegt;属性:“//employee[@no=3304]”

通过工号获取某人的信息;涉及到属性了, 属性使用@;

结果:

(6)获得第一个员工的信息:“//employee[1]”

结果:返回了XML中第一个<employeegt;的信息

(7)获得最后一个员工的信息:“//employee[last()]”

结果:

(8)获取前三个员工:“//employee[position() <4]”

结果:

(9)提取第二个和第四个员工和第五个员工:“//employee[2] | //employee[4] | //employee[5]”

XPath支持组合表达式,用到了“|”;

结果:


注意:

(1)注意扩展到一般,引申;

(2)最重要的是,通过List <Nodegt; nodes = document.selectNodes(xpathExp); ,利用合适xpath表达式获得Node集合;本篇博客为了方便展示结果,采用了打印employee节点的子节点的值的做法;在实际中,可能具体的应用可能不同,但通过Xpath获得List<Nodegt;是最重要的;

(附)/:代表根;//:代表全文搜索,而不管其嵌套顺序和结果;[ ]:代表子元素;@:代表属性;(20210101)