dingsir的个人博客分享 http://blog.sciencenet.cn/u/dingsir

博文

学习笔记: 用XPath查询XML数据

已有 3143 次阅读 2020-8-24 15:29 |个人分类:软件杂谈|系统分类:科研笔记| XML, XML, XML, XML, XML, XPATH, XPATH

基本概念

XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上。因此,对 XPath 的理解是很多高级 XML 应用的基础。

路径表达式的实例

对于以下实例,基于一定的示例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>​

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

路径表达式结果
bookstore选取 bookstore 元素的所有子节点。
/bookstore选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
bookstore/book选取属于 bookstore 的子元素的所有 book 元素。
//book选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang选取名为 lang 的所有属性。

XPath 轴

轴可定义相对于当前节点的节点集。(DxhSay:节点集在使用之时后面接两个冒号)

轴名称结果
ancestor选取当前节点的所有先辈(父、祖父等)。
ancestor-or-self选取当前节点的所有先辈(父、祖父等)以及当前节点本身。
attribute选取当前节点的所有属性
child选取当前节点的所有子元素。
descendant选取当前节点的所有后代元素(子、孙等)。
descendant-or-self选取当前节点的所有后代元素(子、孙等)以及当前节点本身。
following选取文档中当前节点的结束标签之后的所有节点
namespace选取当前节点的所有命名空间节点。
parent选取当前节点的父节点。
preceding选取文档中当前节点的开始标签之前的所有节点。
preceding-sibling选取当前节点之前的所有同级节点。
self选取当前节点。

位置路径表达式

位置路径可以是绝对的,也可以是相对的。绝对路径起始于正斜杠( / ),而相对路径不会这样。在两种情况中,位置路径均包括一个或多个步,每个步均被斜杠分割:

例子结果
child::book选取所有属于当前节点的子元素的 book 节点。
attribute::lang选取当前节点的 lang 属性。
child::*选取当前节点的所有子元素。
attribute::*选取当前节点的所有属性。
child::text()选取当前节点的所有文本子节点。
child::node()选取当前节点的所有子节点。
descendant::book选取当前节点的所有 book 后代。
ancestor::book选择当前节点的所有 book 先辈。
ancestor-or-self::book选取当前节点的所有 book 先辈以及当前节点(如果此节点是 book 节点)
child::*/child::price选取当前节点的所有 price 孙节点。

谓语(Predicates)

谓语用来查找某个特定的节点或者包含某个指定的值的节点。谓语被嵌在方括号中。(修饰或限定之意义,不改变主体级别)

实例

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

路径表达式结果
/bookstore/book[1]选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()]选取属于 bookstore 子元素的最后一个 book 元素。DxhSay:/bookstore/book[count(//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 运算符

下面列出了可用在 XPath 表达式中的运算符:

运算符描述实例返回值
|(集合)并//book | //cd返回所有拥有 book 和 cd 元素的节点集
+加法6 + 410
-减法6 - 42
*乘法6 * 424
div除法8 div 42
=等于price=9.80


!=不等于price!=9.80
<小于price<9.80
<=小于或等于price<=9.80
>大于price>9.80
>=大于或等于price>=9.80
orprice=9.80 or price=9.70
andprice>9.00 and price<9.90运算符的优先级高于and
mod求余5 mod 21

以上内容复制自 W3CSchool, 有部分修改. 以下才是我写的内容


XPATH灵活运用

xpath 函数

上面介绍的XPath功能还不完备,我还要介绍xpath的函数,正是函数使得Xpath更加灵活而强大.

函数名意义注释
text()返回当前节点的文本针对当前节点
comment() 返回节点的注释集合针对当前节点
node()返回当前节点
abs($arg)求绝对值
avg($arg)取平均值
sum($arg)求和

在Oxygen XML Developer有个不错的特性, XPath的输入框中输入路径的斜杠或冒号之后,提示可能使用到的属性或函数,供你选择.

一般来说, 查找数据往往通过限定谓语(即方括号内的内容)来缩小范围,如序号或某个测试条件等. 调整级别通过轴的关系符: parent::, child::,  descendant::, ancestor::等, 数据的并联或去除通过union, except等指令来实现.

完整的清单如下

XPath函数清单.png

XML数据举例

为了实际应用这些XPATH,举一个更复杂的例子,数据如下

<?xml version="1.0" encoding="UTF-8"?>
<样品COA>
    <!--  comments: pls keep the </样品COA> tag.   -->
    <样品记录>
  <序号>1</序号>
  <样品型号>Test001</样品型号>
  <批号>AA1234</批号>
  <水分  单位="ppm">7.7</水分>
  <酸度 单位="ppm" >22.9</酸度>
  <色度 单位="Hazen"><5 </色度>
  <密度 测试温度="25℃" 单位="g/cm3">1.260 </密度>
  <电导率 测试温度="25℃"  单位="mS/cm">9.9</电导率>
  <备注>  </备注>
    </样品记录>
    <样品记录>
  <序号>2</序号>
  <样品型号>Test002</样品型号>
  <批号>AA2345</批号>
  <水分  单位="ppm">5.2</水分>
  <酸度 单位="ppm" >22.3</酸度>
  <色度 单位="Hazen"><5  </色度>
  <密度 测试温度="25℃" 单位="g/cm3">1.253 </密度>
  <电导率 测试温度="25℃"  单位="mS/cm"> 9.7</电导率>
  <备注>  </备注>
    </样品记录>

    <样品记录>
  <序号>3</序号>
  <样品型号>Test003</样品型号>
  <批号>BC20332</批号>
  <水分  单位="ppm">5.6</水分>
  <酸度 单位="ppm" >21.7</酸度>
  <色度 单位="Hazen"><5</色度>
  <密度 测试温度="25℃" 单位="g/cm3">1.241 </密度>
  <电导率 测试温度="25℃"  单位="mS/cm">9.5</电导率>
  <备注>  </备注>
    </样品记录>
    
    <样品记录>
  <序号>4</序号>
  <样品型号>Test006</样品型号>
  <批号>BD23456</批号>
  <水分  单位="ppm">5.7</水分>
  <酸度 单位="ppm" >21.4</酸度>
  <色度 单位="Hazen"><5</色度>
  <密度 测试温度="25℃" 单位="g/cm3">1.264</密度>
  <电导率 测试温度="25℃"  单位="mS/cm">9.8</电导率>
  <备注>  </备注>
    </样品记录>
    
    <样品记录>
  <序号>5</序号>
  <样品型号>Test007</样品型号>
  <批号>AB00332</批号>
  <水分  单位="ppm">5.1</水分>
  <酸度 单位="ppm" >20.3</酸度>
  <色度 单位="Hazen"><5</色度>
  <密度 测试温度="25℃" 单位="g/cm3">1.250</密度>
  <电导率 测试温度="25℃"  单位="mS/cm">10.1</电导率>
  <备注>  </备注>
    </样品记录>
    
</样品COA>

本实例使用上述文本, 测试在oxygen XML Developer 21试用版中进行,使用 Xpath 3.0 进行解析


典型应用案例

  1. 选择所有记录

    /样品COA也就是选择了根目录, 根目录下所有选项.

  2. 查找第1个样品记录

    /样品COA/样品记录[1]

  3. 查询第一条记录的电导率的文本

    /样品COA/样品记录[1]/电导率/text()

  4. 查找倒数第二个样品记录

    /样品COA/样品记录[last()-1]  

    使用last()函数避免了求和函数来计算当前父结点下有多少子项.

    /样品COA/样品记录[count(//样品记录)-1]也可以达到相同的目录.

  5. 查找所有样品记录

    //样品记录  或 /样品COA/样品记录

    开头用//表示查找所有的相关记录,不管它在哪个层级下面.

  6. 查找所有色度

    //色度. 当没有特殊指定其属性时,默认返回的就是色度的文本. 其效果相当于//色度/text(). 记得这是一个集合,尽管有时它只有一项.

  7. 查找色度的单位

    //色度/@单位

  8. 查找色度为<5的记录

    色度的值为<5,而不是某个数值再判断数据是否小于5. 所以下面是等于"<5".

    //色度[.="<5"] 或者是 //色度[text="<5"]

  9. 查找水分值为5.7的记录

    //样品记录[水分=5.7] 或者 //样品记录[child::水分="5.7"]这样得到的是样品记录,而不是水分这个元素.

    还可以 利用parent关系表示为 //水分[.=5.7]/parent::node()

  10. 查找水分值为5.7的元素(指那一个元素, 而不是完整的一个记录)

  //水分[.=5.7]  或  //水分[text()="5.7"]

 11. 查找序号为4的样品记录中, 密度的测试温度是什么?

  //样品记录[序号=4]/密度/@测试温度

 12. 查找水分为5.1, 密度为1.250的记录

 /样品COA/样品记录[水分=5.1 and 密度=1.250]

 13. 查找样品COA下面的第1条注释

 /样品COA/comment()[1]

 14. 查找密度值包含1.260的元素,它的测试温度是多少?

//密度[contains(text(),"1.260")]/@测试温度

从上面的实例中,我们查询密度值为1.260的只有一条记录,因此上面的查询只返回一条记录;如果修改为查找的是包含1.26的,则返回二条记录; contains是一个文本查找函数,比等于号更严谨.有的情况下文本前后可能有空格,使用等号来比较会导致查询失败.

还有一种表示的方法,//密度[number(text())>=1.26 and number(text())<1.30]/@测试温度,把元素的值转化为数字,再对它进行比较. 这与上面的方法不一样,前面是文本比较,这里是数值比较.但结果一样.

 15. 查找酸度值是20.3的样品记录,其电导率的测试温度是多少?

/样品COA/样品记录/酸度[text()=20.3]/parent::node()/电导率/@测试温度

 16. 样品记录1与样品记录3的合集

样品COA/样品记录[1] union /样品COA/样品记录[3] 方括号内不能使用1,3 或1 and 3这样的表示法

 17. 查找不包括样品记录2的合集

/样品COA/样品记录[*] except /样品COA/样品记录[2]

这里用except来处理集合, 从所有集合中除去第2项.

 18. //色度[1]/@单位为什么返回的结果有5项, 我想要的只是第一项的呀?

标题中语句的意思大约是//(色度[1]/@单位), 即所有的(第1个色度元素的单位). 有5个样品记录, 所以有5个结果.

(//色度)[1]/@单位才是你要的. 它的意思是,所有色度元素合集的第1项的单位.它就只有一个.

或者参照第3条的绝对路径的表示方法/样品COA/样品记录[1]/色度/@单位

本博客的PDF文件

本文PDF文档:

链接:https://pan.baidu.com/s/1vuO8C_anHtBSFX8FDg1rJA 

提取码:xpat




https://blog.sciencenet.cn/blog-1213210-1247684.html

上一篇:详解Excel的Open XML中单元格样式的cellStyleXfs,cellStyle,cellXfs之间关系
下一篇:xlwings模块应用的两则小故障及其解决
收藏 IP: 60.191.31.*| 热度|

0

该博文允许注册用户评论 请点击登录 评论 (0 个评论)

数据加载中...

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-11-24 04:22

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部