欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  web前端

XML学习笔记6??XPath语言_html/css_WEB-ITnose

程序员文章站 2022-04-28 15:18:59
...
  在上一篇笔记的结尾,我们接触到了两个用于选择XML文档中特定范围的元素,这两个元素的取值都是XPath表达式,那么,什么是XPath呢?简单的说,XPath是用于在XML文档中查找信息的语言,可用来在XML文档中遍历元素和属性,很多XML的相关技术比如XSLT、XQuery、XPointer等都是构建于XPath的基础之上,在这一篇笔记中,就来学习一下XPath语言。

1、相关术语

(1)节点(Node):格式良好的XML文档都可以转换为一个树型结构,XPath中的节点也就是这个树型结构中的节点。概况起来,有如下所列的七种节点:

节点类型 说明
XML文档根节点 XML文档的根称为文档节点或根节点
元素节点 一个元素的开始标签、结束标签,以及之间的全部内容整体称之为元素节点
属性节点 元素的每个属性都构成一个属性节点,包括属性名称和属性值两个部分,属性节点必须依附于元素节点
命名空间节点 XML文档中的xmlns:prefix属性称之为命名空间节点,注意和属性节点的区别
文本节点 XML元素中间的字符数据,包括CDATA段中的字符数据
注释节点 XML文档里包含的注释部分构成注释节点
处理指令节点 XML文档的处理指令部分构成处理指令节点

(2)基本值(也称为原子值,Atomic Value):专门用于表示简单的字面值,如整数值,字符串等。基本值可以当成没有父节点也没有子节点的节点。

(3)项目(Item):一个项目代表一个基本值或一个节点。

(4)节点集和序列(Sequence):XPath表达式可以表示多个节点,多个节点的组合在XPath1.0中称为节点集,而在XPath2.0中添加了一个序列的术语,即可以代表普通的项目,也可以代表节点集。

(5)节点关系:

节点关系 说明
父节点Parent 每个元素或属性都有一个父节点
子节点Children 元素节点可以有0个、1个或多个子节点
兄弟节点Sibling 父节点相同的节点称之为兄弟节点
祖先节点Ancestor 节点的父节点、父节点的父节点一直到根节点
后代节点Descendant 节点的子节点,子节点的子节点......

(6)相对路径和绝对路径:与操作系统中的路径类似,XPath中也有相对路径和绝对路径,绝对路径以斜线(/)开头,总是从根节点开始匹配,而相对路径则不会以斜线开头,从当前路径开始匹配。

2、XPath语法

  XPath使用路径表达式来访问XML中的节点或节点集,每个XPath表达式总是由一个或多个步(step)组成的,多个步直接使用斜线分隔。在XPath中,步的语法格式如下:

轴::节点测试[限定谓语]

也就是说,每个步都通过了3次筛选,第一次是使用“轴”选择节点方向,第二次使用“节点测试”选取在指定轴方向上的部分节点,第三次则是使用“限定谓语”来对选中的节点进一步过滤。

(1)轴:在XPath中,有下面列表中的各种轴:

轴 简化写法 说明
ancestor 选取当前节点的所有先辈(父、祖父等)节点
ancestor-or-self 选取当前节点的所有先辈(父、祖父等)节点以及当前节点本身
attribute @ 选取当前节点的所有属性节点,如果当前节点不是元素节点,则attribute轴方向上的节点集为空
child 省略不写 选取当前节点的所有子节点
descendant // 选取当前节点的所有后代节点(子、孙等)
descendant-or-self 选取当前节点的所有后代节点(子、孙等)以及当前节点本身
following 选取文档中当前节点的结束标签之后的所有节点,不会包含当前节点的后代节点和属性节点
following-sibling 选取文档中当前节点的结束标签之后的所有兄弟节点
namespace 选取当前节点的所有命名空间节点,当前节点不是元素节点,则namespace轴方向上的节点集为空
parent .. 选取当前节点的父节点
preceding 选取文档中当前节点的开始标签之前的所有节点,不会包含当前节点的后代节点和属性节点
preceding-sibling 选取文档中当前节点的开始标签之前的所有兄弟节点
self . 选取当前节点

(2)节点测试:节点测试用于从指定轴方向上选取所匹配的特定的节点,在XPath中,常用的节点测试语法如下表所示:

节点测试 说明
nodename

从指定轴方向上选出具有nodename的节点

如child::book选择当前节点的所有book子节点

descendant::book选择当前节点的所有book后代节点(包括book子节点、孙子节点等)

node() 选择指定轴匹配的所有类型的节点
text()

选择指定轴匹配的所有文本类型的节点

如child::text()选择当前节点的所有文本子节点

descendant::text()选择当前节点的所有文本后代节点(包括文本子节点、文本孙子节点等)

comment() 选择指定轴匹配的所有注释节点
processing-instruction 选择指定轴匹配的所有处理指令节点
* 节点测试中的通配符,表示所有,也即不进行过滤

(3)限定谓语:每个步中可以接受0个或多个限定谓语,用于进一步过滤所选取的节点集,限定谓语放在方括号中,通常限定谓语返回一个boolean值。看下面的一些例子:

路径表达式 结果
/bookstore/book[1] 选取属于 bookstore 元素的子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 元素的子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 元素的子元素的倒数第二个 book 元素。
/bookstore/book[position() 选取最前面的两个属于 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。

3、运算符

  从上面的实例中可以看到,在限定谓语中,还可以使用运算符、表达式,还有很多内置的函数供使用。这一小节先看看XPath中支持的运算符:

(1)算术运算符:加(+)、减(-)、乘(*)、除(div)、取模(mod)

  算术运算符非常简单,但是需要注意几点:

A、因为减号实际上也就是中划线,而中划线在XML中是合法的标识符号,从而带来了歧义,于是XPath强制规定,使用减号的时候,需要前后各加一个空格。

B、在XPath中,所有的数值都是64位的double类型,即便直接书写成0、100;另外,XPath还有几个特殊的数值:正无穷大、负无穷大、非数。

C、在运算时,如果操作数不是数值类型,会自动转换,下面的比较运算符、逻辑运算符如果有必要也会发生相应的自动类型转换。

(2)比较运算符:等于(=)、不等于(!=)、小于()、大于或等于(>=)

  需要注意的是,不像其它编程语言,这里表示相等只需要一个等于号。

(3)逻辑运算符:与(and)、或(or)

(4)集合运算符:并集(|)

4、表达式

(1)for表达式:用于循环访问序列中的每个项,并对每项进行一次计算,最后将每项计算得到的结果组合成序列后返回,语法格式如下:

for $var in sequence return rtExpression

实际上,这里的for更类似于js中的foreach。还可以使用下面的形式遍历多个序列:

for $var1 in sequence1, $var2 in sequence2 return fn($var1,$var2)

(2)if表达式:用于处理分支,根据不同条件得到不同的返回值,语法格式如下:

if (condition1)then rtVal1[else if (condition2)then rtVal2...]elseotherVal

(3)some表达式:迭代中只要有一项满足条件就返回true,否则返回false,语法格式如下:

some $var in sequence satisfies condition

(4)every表达式:迭代中只有有一项不满足条件就返回false,否则返回true,语法格式如下:

every $var in sequence satisfies condition

5、内置函数库

  在XPath中还有大量的内置函数,用于增强相关功能,这些内置函数可以参考:XPath函数。我在下面也抄录一份供参考:

分类 函数 说明
存取函数 fn:node-name(node) 返回参数节点的节点名称。
fn:nilled(node) 返回是否拒绝参数节点的布尔值。
fn:data(item.item,...) 接受项目序列,并返回原子值序列。
fn:base-uri() fn:base-uri(node) 返回当前节点或指定节点的 base-uri 属性的值。
fn:document-uri() fn:document-uri(node) 返回当前节点或指定节点的 document-uri 属性的值。
错误和跟踪函数 fn:error() fn:error(error) fn:error(error,description) fn:error(error,description,error-object)

例子:error(fn:QName('http://example.com/test', 'err:toohigh'), 'Error: Price is too high')

结果:向外部处理环境返回 http://example.com/test#toohigh 以及字符串 "Error: Price is too high"。

fn:trace(value,label) 用于对查询进行 debug。
数值函数 fn:number(arg)

返回参数的数值。参数可以是布尔值、字符串或节点集。

例子:number('100')

结果:100

fn:abs(num) 返回参数的绝对值。
fn:ceiling(num) 返回大于或等于 num 参数的最小整数。
fn:floor(num) 返回小于或等于 num 参数的最大整数。
fn:round(num) 把 num 参数四舍五入为最接近的整数。
fn:round-half-to-even()

返回最接近参数num的偶数

例子:round-half-to-even(0.5) 结果:0

例子:round-half-to-even(1.5) 结果:2

例子:round-half-to-even(2.5) 结果:2

字符串函数 fn:string(arg) 返回参数的字符串值。参数可以是数字、逻辑值或节点集。
fn:codepoints-to-string(int,int,...)

根据一个Unicode值序列序列返回字符串。

例子:codepoints-to-string((84, 104, 233, 114, 232, 115, 101))

结果:'Thérèse'

注意:该函数的参数是一个Unicode值序列,因此必须用括号将参数括起来

fn:string-to-codepoints(string) 根据字符串返回每个字符所对应的Unicode值的序列。
fn:codepoint-equal(comp1,comp2) 根据 Unicode 值序列比较,如果 comp1 的值等于 comp2 的值,则返回 true,否则返回 false。
fn:compare(comp1,comp2) fn:compare(comp1,comp2,collation)

根据对照规则,comp1小于comp2返回 -1;comp1等于comp2,返回0;comp1大于comp2返回1。

fn:concat(string,string,...) 返回字符串的拼接。
fn:string-join((string,string,...),sep) 使用 sep 参数作为分隔符,来返回 string 参数拼接后的字符串。
fn:substring(string,start,len) fn:substring(string,start)

返回从 start 位置开始的指定长度的子字符串。第一个字符的下标是 1。

如果省略 len 参数,则返回从位置 start 到字符串末尾的子字符串。

fn:string-length(string) fn:string-length() 返回指定字符串的长度。如果没有 string 参数,则返回当前节点的字符串值的长度
fn:normalize-space(string) fn:normalize-space() 删除指定字符串的首尾空白,并把内部连续空白压缩为一个,然后返回结果。没有参数,则处理当前节点。
fn:normalize-unicode() 执行 Unicode 规格化。
fn:upper-case(string) 把 string 参数转换为大写。
fn:lower-case(string) 把 string 参数转换为小写。
fn:translate(string1,string2,string3)

把 string1 中的 string2 替换为 string3。

例子:translate('12:30','30','45')

结果:'12:45'

例子:translate('12:30','03','54')

结果:'12:45'

例子:translate('12:30','0123','abcd')

结果:'bc:da'

fn:escape-uri(stringURI,esc-res)

例子:escape-uri("http://example.com/test#car", true())

结果:"http%3A%2F%2Fexample.com%2Ftest#car"

例子:escape-uri("http://example.com/test#car", false())

结果:http://example.com/test#car

例子:escape-uri ("http://example.com/~bébé", false())

结果:"http://example.com/~b%C3%A9b%C3%A9"

fn:contains(string1,string2) 如果 string1 包含 string2,则返回 true,否则返回 false。
fn:starts-with(string1,string2) 如果 string1 以 string2 开始,则返回 true,否则返回 false。
fn:ends-with(string1,string2) 如果 string1 以 string2 结尾,则返回 true,否则返回 false。
fn:substring-before(string1,string2) 返回 string2 在 string1 中出现之前的子字符串。
fn:substring-after(string1,string2) 返回 string2 在 string1 中出现之后的子字符串。
fn:matches(string,pattern) 如果 string 参数匹配指定的模式,则返回 true,否则返回 false。
fn:replace(string,pattern,replace) 把指定的模式替换为 replace 参数,并返回结果。
fn:tokenize(string,pattern)

例子:tokenize("XPath is fun", "\s+")

结果:("XPath", "is", "fun")

anyURI函数 fn:resolve-uri(relative,base)
逻辑函数 fn:boolean(arg) 返回数字、字符串或节点集的布尔值。
fn:not(arg) 首先通过 boolean() 函数把参数还原为一个布尔值,然后再取反。
fn:true() 返回布尔值 true。
fn:false() 返回布尔值 false。
日期时间函数 fn:dateTime(date,time) 把参数转换为日期和时间。
fn:years-from-duration(datetimedur) 返回参数值的年份部分的整数,以标准词汇表示法来表示。
fn:months-from-duration(datetimedur) 返回参数值的月份部分的整数,以标准词汇表示法来表示。
fn:days-from-duration(datetimedur) 返回参数值的天部分的整数,以标准词汇表示法来表示。
fn:hours-from-duration(datetimedur) 返回参数值的小时部分的整数,以标准词汇表示法来表示。
fn:minutes-from-duration(datetimedur) 返回参数值的分钟部分的整数,以标准词汇表示法来表示。
fn:seconds-from-duration(datetimedur) 返回参数值的分钟部分的十进制数,以标准词汇表示法来表示。
fn:year-from-dateTime(datetime) 返回参数本地值的年部分的整数。
fn:month-from-dateTime(datetime) 返回参数本地值的月部分的整数。
fn:day-from-dateTime(datetime) 返回参数本地值的天部分的整数。
fn:hours-from-dateTime(datetime) 返回参数本地值的小时部分的整数。
fn:minutes-from-dateTime(datetime) 返回参数本地值的分钟部分的整数。
fn:seconds-from-dateTime(datetime) 返回参数本地值的秒部分的十进制数。
fn:timezone-from-dateTime(datetime) 返回参数的时区部分,如果存在。
fn:year-from-date(date) 返回参数本地值中表示年的整数。
fn:month-from-date(date) 返回参数本地值中表示月的整数。
fn:day-from-date(date) 返回参数本地值中表示天的整数。
fn:timezone-from-date(date) 返回参数的时区部分,如果存在。
fn:hours-from-time(time) 返回参数本地值中表示小时部分的整数。
fn:minutes-from-time(time) 返回参数本地值中表示分钟部分的整数。
fn:seconds-from-time(time) 返回参数本地值中表示秒部分的整数。
fn:timezone-from-time(time) 返回参数的时区部分,如果存在。
fn:adjust-dateTime-to-timezone(datetime,timezone) 如果 timezone 参数为空,则返回没有时区的 dateTime。否则返回带有时区的 dateTime。
fn:adjust-date-to-timezone(date,timezone) 如果 timezone 参数为空,则返回没有时区的 date。否则返回带有时区的 date。
fn:adjust-time-to-timezone(time,timezone) 如果 timezone 参数为空,则返回没有时区的 time。否则返回带有时区的 time。
QName相关函数 fn:QName()
fn:local-name-from-QName()
fn:namespace-uri-from-QName()
fn:namespace-uri-for-prefix()
fn:in-scope-prefixes()
fn:resolve-QName()
节点函数 fn:name() fn:name(nodeset) 返回当前节点的名称或指定节点集中的第一个节点。
fn:local-name() fn:local-name(nodeset) 返回当前节点的名称或指定节点集中的第一个节点 - 不带有命名空间前缀。
fn:namespace-uri() fn:namespace-uri(nodeset) 返回当前节点或指定节点集中第一个节点的命名空间 URI。
fn:lang(lang)

如果当前节点的语言匹配指定的语言,则返回 true。

例子:Lang("en") is true for

...

例子:Lang("de") is false for

...

fn:root() fn:root(node) 返回当前节点或指定的节点所属的节点树的根节点。通常是文档节点。
上下文函数 fn:position()

返回当前正在被处理的节点的 index 位置。

例子://book[position()

结果:选择前三个 book 元素

fn:last()

返回在被处理的节点列表中的项目数目。

例子://book[last()]

结果:选择最后一个 book 元素

fn:current-dateTime() 返回当前的 dateTime(带有时区)。
fn:current-date() 返回当前的日期(带有时区)。
fn:current-time() 返回当前的时间(带有时区)。
fn:implicit-timezone() 返回隐式时区的值。
fn:default-collation() 返回默认对照的值。
fn:static-base-uri() 返回 base-uri 的值。
序列函数 一般序列函数 fn:index-of((item,item,...),searchitem)

返回在项目序列中等于 searchitem 参数的位置。

例子:index-of ((15, 40, 25, 40, 10), 40)

结果:(2, 4)

fn:remove((item,item,...),position) 返回由 item 参数构造的新序列 - 同时删除 position 参数指定的项目。
fn:empty(item,item,...) 如果参数值是空序列,则返回 true,否则返回 false。
fn:exists(item,item,...) 如果参数值不是空序列,则返回 true,否则返回 false。
fn:distinct-values((item,item,...),collation)

返回唯一不同的值。

例子:distinct-values((1, 2, 3, 1, 2))

结果:(1, 2, 3)

fn:insert-before((item,item,...),pos,inserts) 返回由 item 参数构造的新序列 - 同时在 pos 参数指定位置插入 inserts 参数的值。
fn:reverse((item,item,...)) 返回指定的项目的颠倒顺序。
fn:subsequence((item,item,...),start,len) 返回 start 参数指定的位置返回项目序列,序列的长度由 len 参数指定。第一个项目的位置是 1。
fn:unordered((item,item,...)) 依据实现决定的顺序来返回项目。
容量测试函数 fn:zero-or-one(item,item,...) 如果参数包含零个或一个项目,则返回参数,否则生成错误。
fn:one-or-more(item,item,...) 如果参数包含一个或多个项目,则返回参数,否则生成错误。
fn:exactly-one(item,item,...) 如果参数包含一个项目,则返回参数,否则生成错误。
比较函数 fn:deep-equal(param1,param2,collation) 如果 param1 和 param2 与彼此相等(deep-equal),则返回 true,否则返回 false。
合计函数 fn:count((item,item,...)) 返回节点的数量。
fn:avg((arg,arg,...)) 返回参数值的平均数。
fn:max((arg,arg,...)) 返回参数中的最大值。
fn:min((arg,arg,...)) 返回参数中的最小值。
fn:sum(arg,arg,...) 返回指定节点集中每个节点的数值的总和。
序列生成函数 fn:id((string,string,...),node)
fn:idref((string,string,...),node)
fn:data((item1,item2,...)) 返回item1、item2等各项的值所组成的序列。
fn:doc(URI)
fn:doc-available(URI) 如果 doc() 函数返回文档节点,则返回 true,否则返回 false。
fn:collection() fn:collection(string)

很明显,把这些内置函数放在这里的目的并不是要强行记住,而只是需要的时候当字典查查(XQuery1.0和XPath共享了这些内置函数,有事没事看看,混个眼熟也挺好的)。