一,为什么要用xpath技术
假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击http://106.12.206.16:8080/qingruihappy/index.html
问题:当使用dom4j查询比较深的层次结构的节点(标签,属性,文本),比较麻烦!!!
二,xpath的规则
2.1,/根元素的案例
/AAA |
---|
选择根元素AAA |
<AAA> <BBB/> <CCC/> <BBB/> <BBB/> <DDD> <BBB/> </DDD> <CCC/> </AAA> |
/AAA/CCC |
---|
选择AAA的所有CCC子元素 |
<AAA> <BBB/> <CCC/> <BBB/> <BBB/> <DDD> <BBB/> </DDD> <CCC/> </AAA> |
/AAA/DDD/BBB |
---|
选择AAA的子元素DDD的所有子元素 |
<AAA> <BBB/> <CCC/> <BBB/> <BBB/> <DDD> <BBB/> </DDD> <CCC/> </AAA> |
2.2,以双斜线 // 开头则表示选择文档中所有满足双斜线//之后规则的元素(无论层级关系)
//BBB |
---|
选择所有BBB元素 |
<AAA> <BBB/> <CCC/> <BBB/> <DDD> <BBB/> </DDD> <CCC> <DDD> <BBB/> <BBB/> </DDD> </CCC> </AAA> |
//DDD/BBB |
---|
选择所有父元素是DDD的BBB元素 |
<AAA> <BBB/> <CCC/> <BBB/> <DDD> <BBB/> </DDD> <CCC> <DDD> <BBB/> <BBB/> </DDD> </CCC> </AAA> |
2.3,星号 * 表示选择所有由星号之前的路径所定位的元素
/AAA/CCC/DDD/* |
---|
选择所有路径依附于/AAA/CCC/DDD的元素 |
<AAA> <XXX> <DDD> <BBB/> <BBB/> <EEE/> <FFF/> </DDD> </XXX> <CCC> <DDD> <BBB/> <BBB/> <EEE/> <FFF/> </DDD> </CCC> <CCC> <BBB> <BBB> <BBB/> </BBB> </BBB> </CCC> </AAA> |
/*/*/*/BBB |
---|
选择所有的有3个祖先元素的BBB元素 |
<AAA> <XXX> <DDD> <BBB/> <BBB/> <EEE/> <FFF/> </DDD> </XXX> <CCC> <DDD> <BBB/> <BBB/> <EEE/> <FFF/> </DDD> </CCC> <CCC> <BBB> <BBB> <BBB/> </BBB> </BBB> </CCC> </AAA> |
//* |
---|
选择所有元素 |
<AAA> <XXX> <DDD> <BBB/> <BBB/> <EEE/> <FFF/> </DDD> </XXX> <CCC> <DDD> <BBB/> <BBB/> <EEE/> <FFF/> </DDD> </CCC> <CCC> <BBB> <BBB> <BBB/> </BBB> </BBB> </CCC> </AAA> |
2.4,方块号里的表达式可以进一步的指定元素, 其中数字表示元素在选择集里的位置, 而last()函数则表示选择集中的最后一个元素.
/AAA/BBB[1] |
---|
选择AAA的第一个BBB子元素 |
<AAA> <BBB/> <BBB/> <BBB/> <BBB/> </AAA> |
/AAA/BBB[last()] |
---|
选择AAA的最后一个BBB子元素 |
<AAA> <BBB/> <BBB/> <BBB/> <BBB/> </AAA> |
2.5,属性通过前缀 @ 来指定
//@id |
---|
选择所有的id属性 |
<AAA> <BBB id = "b1"/> <BBB id = "b2"/> <BBB name = "bbb"/> <BBB/> </AAA> |
//BBB[@id] |
---|
选择有id属性的BBB元素 |
<AAA> <BBB id = "b1"/> <BBB id = "b2"/> <BBB name = "bbb"/> <BBB/> </AAA> |
//BBB[@name] |
---|
选择有name属性的BBB元素 |
<AAA> <BBB id = "b1"/> <BBB id = "b2"/> <BBB name = "bbb"/> <BBB/> </AAA> |
//BBB[@*] |
---|
选择有任意属性的BBB元素 |
<AAA> <BBB id = "b1"/> <BBB id = "b2"/> <BBB name = "bbb"/> <BBB/> </AAA> |
//BBB[not(@*)] |
---|
选择没有属性的BBB元素 |
<AAA> <BBB id = "b1"/> <BBB id = "b2"/> <BBB name = "bbb"/> <BBB/> </AAA> |
2.6,属性的值可以被用来作为选择的准则, normalize-space函数删除了前部和尾部的空格, 并且把连续的空格串替换为一个单一的空格
//BBB[@id='b1'] |
---|
选择含有属性id且其值为'b1'的BBB元素 |
<AAA> <BBB id = "b1"/> <BBB name = " bbb "/> <BBB name = "bbb"/> </AAA> |
//BBB[@name='bbb'] |
---|
选择含有属性name且其值为'bbb'的BBB元素 |
<AAA> <BBB id = "b1"/> <BBB name = " bbb "/> <BBB name = "bbb"/> </AAA> |
//BBB[normalize-space(@name)='bbb'] |
---|
选择含有属性name且其值(在用normalize-space函数去掉前后空格后)为'bbb'的BBB元素 |
<AAA> <BBB id = "b1"/> <BBB name = " bbb "/> <BBB name = "bbb"/> </AAA> |
2.7,总结
还有其它的很多的语法,请详见XPathTutorial这个api
下面几个是常见的符号
1 / 绝对路径 表示从xml的根位置开始或子元素(一个层次结构) 2 // 相对路径 表示不分任何层次结构的选择元素。 3 * 通配符 表示匹配所有元素 4 [] 条件 表示选择什么条件下的元素 5 @ 属性 表示选择属性节点 6 and 关系 表示条件的与关系(等价于&&) 7 text() 文本 表示选择文本内容
三,案例
3.1,删除id值为2的学生标签
1 /** 2 * 需求: 删除id值为2的学生标签 3 */ 4 Document doc = new SAXReader().read(new File("e:/student.xml")); 5 6 //1.查询id为2的学生标签 7 //使用xpath技术 8 Element stuElem = (Element)doc.selectSingleNode("//Student[@id='2']"); 9 10 //2.删除标签 11 stuElem.detach(); 12 13 //3.写出xml文件 14 FileOutputStream out = new FileOutputStream("e:/student.xml"); 15 OutputFormat format = OutputFormat.createPrettyPrint(); 16 format.setEncoding("utf-8"); 17 XMLWriter writer = new XMLWriter(out,format); 18 writer.write(doc); 19 writer.close();
3.2,常用符号的应用
1 Document doc = new SAXReader().read(new File("./src/contact.xml")); 2 3 String xpath = ""; 4 5 /** 6 * 1. / 绝对路径 表示从xml的根位置开始或子元素(一个层次结构) 7 */ 8 xpath = "/contactList"; 9 xpath = "/contactList/contact"; 10 11 /** 12 * 2. // 相对路径 表示不分任何层次结构的选择元素。 13 */ 14 xpath = "//contact/name"; 15 xpath = "//name"; 16 17 /** 18 * 3. * 通配符 表示匹配所有元素 19 */ 20 xpath = "/contactList/*"; //根标签contactList下的所有子标签 21 xpath = "/contactList//*";//根标签contactList下的所有标签(不分层次结构) 22 23 /** 24 * 4. [] 条件 表示选择什么条件下的元素 25 */ 26 //带有id属性的contact标签 27 xpath = "//contact[@id]"; 28 //第二个的contact标签 29 xpath = "//contact[2]"; 30 //选择最后一个contact标签 31 xpath = "//contact[last()]"; 32 33 /** 34 * 5. @ 属性 表示选择属性节点 35 */ 36 xpath = "//@id"; //选择id属性节点对象,返回的是Attribute对象 37 xpath = "//contact[not(@id)]";//选择不包含id属性的contact标签节点 38 xpath = "//contact[@id='002']";//选择id属性值为002的contact标签 39 xpath = "//contact[@id='001' and @name='eric']";//选择id属性值为001,且name属性为eric的contact标签 40 41 /** 42 *6. text() 表示选择文本内容 43 */ 44 //选择name标签下的文本内容,返回Text对象 45 xpath = "//name/text()"; 46 xpath = "//contact/name[text()='张三']";//选择姓名为张三的name标签 47 48 49 List<Node> list = doc.selectNodes(xpath); 50 for (Node node : list) { 51 System.out.println(node); 52 } 53 }
3.3,按照规定格式输出内容
1 <html> 2 <head> 3 <title>传智播客1月18号班通讯录</title> 4 <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> 5 </head> 6 <body> 7 <center><h1>12月16号就业班通讯录</h1></center> 8 <table border="1" align="center" id="contactForm"> 9 <thead> 10 <tr><th>编号</th><th>姓名</th><th>性别</th><th>年龄</th><th>地址</th><th>电话</th></tr> 11 </thead> 12 <tbody> 13 <tr> 14 <td>001</td> 15 <td>张三</td> 16 <td>男</td> 17 <td>18</td> 18 <td>广州市天河区</td> 19 <td>134000000000</td> 20 </tr> 21 <tr> 22 <td>002</td> 23 <td>李四</td> 24 <td>女</td> 25 <td>20</td> 26 <td>广州市越秀区</td> 27 <td>13888888888</td> 28 </tr> 29 <tr> 30 <td>002</td> 31 <td>郭靖</td> 32 <td>男</td> 33 <td>30</td> 34 <td>广州市番禺区</td> 35 <td>1342214321</td> 36 </tr> 37 </tbody> 38 </table> 39 </body> 40 </html>
1 public static void main(String[] args) throws Exception{ 2 Document doc = new SAXReader().read(new File("./src/personList.html")); 3 //System.out.println(doc); 4 5 //读取title标签 6 Element titleElem = (Element)doc.selectSingleNode("//title"); 7 String title = titleElem.getText(); 8 System.out.println(title); 9 10 /** 11 * 练习:读取联系人的所有信息 12 * 按照以下格式输出: 13 * 编号:001 姓名:张三 性别:男 年龄:18 地址:xxxx 电话: xxxx 14 * 编号:002 姓名:李四 性别:女 年龄:20 地址:xxxx 电话: xxxx 15 * ...... 16 */ 17 //1.读取出所有tbody中的tr标签 18 List<Element> list = (List<Element>)doc.selectNodes("//tbody/tr"); 19 //2.遍历 20 for (Element elem : list) { 21 //编号 22 //String id = ((Element)elem.elements().get(0)).getText(); 23 String id = elem.selectSingleNode("td[1]").getText(); 24 //姓名 25 String name = ((Element)elem.elements().get(1)).getText(); 26 //性别 27 String gender = ((Element)elem.elements().get(2)).getText(); 28 //年龄 29 String age = ((Element)elem.elements().get(3)).getText(); 30 //地址 31 String address = ((Element)elem.elements().get(4)).getText(); 32 //电话 33 String phone = ((Element)elem.elements().get(5)).getText(); 34 35 System.out.println("编号:"+id+"\t姓名:"+name+"\t性别:"+ 36 gender+"\t年龄:"+ 37 age+"\t地址:"+address+ 38 "\t电话:"+phone); 39 } 40 }
1 传智播客1月18号班通讯录 2 编号:001 姓名:张三 性别:男 年龄:18 地址:广州市天河区 电话:134000000000 3 编号:002 姓名:李四 性别:女 年龄:20 地址:广州市越秀区 电话:13888888888 4 编号:002 姓名:郭靖 性别:男 年龄:30 地址:广州市番禺区 电话:1342214321
补充
XPath 运算符
下面列出了可用在 XPath 表达式中的运算符:
运算符 | 描述 | 实例 | 返回值 |
---|---|---|---|
| | 计算两个节点集 | //book | //cd | 返回所有拥有 book 和 cd 元素的节点集 |
+ | 加法 | 6 + 4 | 10 |
- | 减法 | 6 - 4 | 2 |
* | 乘法 | 6 * 4 | 24 |
div | 除法 | 8 div 4 | 2 |
= | 等于 | price=9.80 | 如果 price 是 9.80,则返回 true。 如果 price 是 9.90,则返回 false。 |
!= | 不等于 | price!=9.80 | 如果 price 是 9.90,则返回 true。 如果 price 是 9.80,则返回 false。 |
< | 小于 | price<9.80 | 如果 price 是 9.00,则返回 true。 如果 price 是 9.90,则返回 false。 |
<= | 小于或等于 | price<=9.80 | 如果 price 是 9.00,则返回 true。 如果 price 是 9.90,则返回 false。 |
> | 大于 | price>9.80 | 如果 price 是 9.90,则返回 true。 如果 price 是 9.80,则返回 false。 |
>= | 大于或等于 | price>=9.80 | 如果 price 是 9.90,则返回 true。 如果 price 是 9.70,则返回 false。 |
or | 或 | price=9.80 or price=9.70 | 如果 price 是 9.80,则返回 true。 如果 price 是 9.50,则返回 false。 |
and | 与 | price>9.00 and price<9.90 | 如果 price 是 9.80,则返回 true。 如果 price 是 8.50,则返回 false。 |
mod | 计算除法的余数 | 5 mod 2 | 1 |