跳转到内容

XML/XPath

维基教科书,自由的教学读本
< XML

XML > XPath


XPath

[编辑]

学习目标

[编辑]

完成本章的学习后,您将能够:

  • 形成这样的概念:一个XML文档是一棵节点树
  • 在XML文档中引用元素组
  • 了解简写与非简写XPath语法的不同
  • 了解绝对路径与相对路径的不同
  • 使用XPath谓词和函数提炼出一个XPath节点集

概述

[编辑]
在前面的章节中您已经学习了XSL。进行XSL转换时基本上都必须引用XML文档中的节点。目前常使用一种简单易懂

的语法来引用XML文档中的节点。这种语法就是XPath。当然XPath具有更多我们尚未利用的特征和能力。本章将深 入介绍XPath这种XML的路径语言,常用于引用XML文档中的节点。

本章将对XPath语法进行简要的概括,但这足以使您了解它的基本概念。想全面地深入认识XPath,请察看最新版

本的标准:

http://www.w3.org/TR/xpath

您也可以暂时松一口气,因为本章不会用到XML schemas。介绍XPath的概念时无须使用XML schemas。而能够展

现XPath能力的则是XSL,在XSL中常常使用XPath。

XPath

[编辑]
在*nix或Windows系统中复制一个文件或进入一层目录时,通常会在命令提示符后输入诸如“/home/darnell/”

或“C:\MyFiles\”之类来引用文件夹。借此您可以进入或引用计算机文件系统中的文件夹。XML使用类似的方法来 引用XML文档中的元素。这种特殊的语法就是XPath,即XML路径语言(XML Path Language)的缩写。

尽管XPath用于引用XML树的节点,它本身并不以XML格式书写。对于W3C,这是一个明智的做法,因为用XML表示

路径信息非常困难。任何形成XML语法的字符都必须进行转义,以免在处理时与XML混淆。而Xpath却十分简洁,可 以有针对性地引用XML树中节点,可以避免不必要的冗长表示。

XML 的树形结构

[编辑]
我们可以把一个XML文档看作是一个树形结构,文档的顶端是树根。树上的每个元素都可称为节点(node)。顶层

元素称为“根节点”,所有包含在其中的标签都是它的后继节点。图9-1是一个HTML文档,显示了XML文档的树形结构。

http://ebiz.terry.uga.edu/~darford/XPath-9_1.PNG

图9-1一个基本HTML文档的树形模型

节点关系

[编辑]
在树形结构中,节点<html> 是元素 <head> 和 <body> 的父节点(parent)。 它也是除

“根”元素外其他所有节点的祖先节点(ancestor),根元素没有祖先节点。本例中,标签<p> 是 <body>的子节点(child)。 标签 <p> 也可被认为是“根”元素、节点<html>,和 <body>的后继节点(descendant),因为它在树中处于较低级的位置。如果两个节点拥有同一个父节点, 例如<head> 和<body>,它们将被称为兄弟节点(siblings)。

就像在XML编辑器中看到的那样,有时我们把XML文档看成是序列化文档。这样有助于理解前趋节点和后续节点的概

念。按照文档顺序,如果一个节点位于另一个节点之前,那么称前者为后者的前趋节点(precede)。同样,如果一 个节点位于另一个节点之后,那么称前者为后者的后续节点(follow)。祖先节点和子孙节点是不考虑是否前趋于 某一节点或后续于某一节点的。在后面讨论轴(axis)时这些概念会变得清晰些。

简写的XPath语法与非简写的XPath语法

[编辑]
建立XPath可使节点的引用变得简洁,同时保持进行多选项的搜索的能力。大多数XPath的使用者会搜索某一特定

节点的子节点、父节点或属性节点。因为这样的行为比较普遍,在引用这些经常被搜索的节点时可以使用简写的语 法。下面是一个树形的XML文档(具有叶子和分支),它将用于表示不同种类的语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

<?xml version="1.0" encoding="UTF-8"?>
<trunk name="the_trunk">
<bigBranch name="bb1" thickness="thick">
<smallBranch name="sb1">
<leaf name="leaf1" color="brown" />
<leaf name="leaf2" weight="50" />
<leaf name="leaf3" />
</smallBranch>
<smallBranch name="sb2">
<leaf name="leaf4" weight="90" />
<leaf name="leaf5" color="purple" />
</smallBranch>
</bigBranch>
<bigBranch name="bb2">
<smallBranch name="sb3">
<leaf name="leaf6" />
</smallBranch>
<smallBranch name="sb4">
<leaf name="leaf7" />
<leaf name="leaf8" />
<leaf name="leaf9" color="black" />
<leaf name="leaf10" weight="100" />
</smallBranch>
</bigBranch>
<bigBranch name="bb3" thickness="thin">
<smallBranch name="sb5" color="lightBrown" >
<leaf name="leaf11" />
<leaf name="leaf12" />
</smallBranch>
<smallBranch name="sb6" thickness="thin">
<leaf name="leaf13" weight="2" />
<leaf name="leaf14" color="red" />
<leaf name="leaf15" />
</smallBranch>
<smallBranch name="sb7">
<leaf name="leaf16" />
<leaf name="leaf17" color="red" />
</smallBranch>
</bigBranch>
</trunk>

图9-2 tree. xml – XML 页示例

以下是其中一些XPath定位路径的示例,包括简写的和未简写的XPath:


示例1:

意义: 在上面文档中所有的 <leaf> 元素都是<smallBranch> 元素的子节点,而 <smallBranch>元素是<bigBranch>元素的子节点,<bigBranch>元素是trunk的子节 点,trunk又是根的子节点。
简写: /trunk/bigBranch/smallBranch/leaf
未简写: /child::trunk/child::bigBranch/child::smallBranch/child::leaf

示例 2:

意义: <bigBranch> 元素的name属性为“bb3”,是trunk元素的子节点,trunk元素是根的子节点。
简写: /trunk/bigBranch[@name=’bb3’]
未简写: /child::trunk/child::bigBranch[attribute::name=’bb3’]

注意示例中如何利用谓词来指定所需要的bigBranch。这使搜索范围缩小,只搜索那些满足谓词条件的bigBranch

节点。谓词是方括号中XPath语句的一部分。本例中谓词要求bigBranch节点的name属性值为“bb3”。

以上两个示例是假定指定从根开始的路径。下面的示例则指定从一个<smallBranch>节点开始的路径:


示例 3:

意义:当前<smallBranch&gt节点的父节点。(注意本例是相对于 <smallBranch>节点来看的)
简写: ..
未简写: parent::node()

采用未简写语法时必须注意,被调用父节点或子节点的后面应该跟着两个冒号(::),冒号之前的节点称为轴

(axis)。后面的小节将会讲解更多关于轴的知识。

现在正好来解释一下定位路径(location path)的概念。定位路径是指为到达指定节点所采取的一系列定位步骤

(location steps)。定位步骤是XPath语句的一部分,被字符“/”隔开。它们是在寻找指定节点过程所经过的 每一步。

定位步骤由3部分构成:轴(axis)(子节点,父节点,子孙节点等等),节点测试(node test)(节点名称,

或者是可返回一个或多个节点的函数),以及一系列谓词(检验返回的节点以缩小搜索结果的范围,去掉那些没有通 过谓词检验的节点)。

因此,在一个定位路径中每一个定位步骤都会返回一个节点列表。如果路径在某一定位步骤没有结束,那么将会对

本次定位步骤所返回的所有节点执行下一步操作。

相对路径 与 绝对路径

[编辑]
用Xpath可以指定两种路径,一种情况是 已经“处于一个节点之中”的路径,另一种情况则是选择从根节点开始的

路径。熟悉HTML网站的人会发现,HTML超级链接也是使用同样的方法来引用其它文件的。在HTML中,可以为超级链 接指定一个绝对路径(absolute path),在URL中描述该页所在的服务器名,文件夹和文件名。如果所引用的文 件在同一站点上,就不需要输入服务器名和完整的路径信息。这被称为是相对路径(relative path)。这些概念 在XPath中也同样被采用。

两者的不同则体现在XPath表达式的开始位置是否存在字符‘/’。如果有,表明这是一个绝对路径,是从根开始的

路径。如果没有,表明这是一个相对路径,只是描述当前节点与前后节点的关系,或是下一步要使用的节点。

下面是一个XSL样式表(图9-3),它用到了图9-2中的树形XML文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>

<xsl:template match="/child::trunk">
<html>
<head>
<title>XPath Tree Tests</title>
</head>
<body>
<xsl:for-each select="child::bigBranch">
<xsl:call-template name="print_out" />
</xsl:for-each>
</body>
</html>
</xsl:template>

<xsl:template name="print_out">
<xsl:value-of select="attribute::name" /><br />
</xsl:template>

</xsl:stylesheet>

图 9-3 xsl_tree.xsl – 绝对路径和相对路径的示例

在上面的代码中,第5行是一个绝对链接的示例。元素‘/child::trunk'’是从根元素开始指定的。第12行是一个相对链接的示例。<for-each> xsl 语句会在“当前”节点中的每一个<bigBranch> 节点上执行,而这个“当前”节点正是<trunk> 节点。

四种XPath定位路径

[编辑]
上面两个小节介绍了定位路径的两类区别:简写路径与未简写路径,相对路径与绝对路径。结合这两类概念有助于

理解XPath定位路径。当您在朋友面前这样谈论事物时,会显得您的思路十分有条理:

  1. 简写的相对定位路径
  2. 简写的绝对定位路径
  3. 未简写的相对定位路径
  4. 未简写的绝对定位路径
此处仅列出了4种不同的方式,通过阅读相关材料,能够很容易地得到上述将定位路径分为4类的区分方式。

XPath轴

[编辑]
在XPath中,有些节点需要使用未简写的语法来进行选择。在这种情况下,就要使用轴来指定定位路径中的每一个定位步骤。
从树上的任意节点出发,都有13个轴可以使用,它们是:


含义
ancestor:: 由当前节点向上,从父节点至根节点
ancestor-or-self:: 由当前节点向上,从当前节点到父节点直至根节点 attribute:: 当前节点的属性(Attributes of the current node) child:: 当前节点的直接子节点(Immediate children of the current node) descendant:: 当前节点的子孙节点(包括子节点的子节点) descendant-or-self:: 当前节点的子孙节点以及当前节点本身 following:: 当前节点的后续节点(子节点除外) following-sibling:: 与当前节点处于同一层的后续节点(子节点除外) namespace:: 当前节点的XML 命名空间 parent:: 当前节点的直接父节点 preceding:: 当前节点的前趋节点(子节点除外) preceding-sibling:: 与当前节点处于同一层的前趋节点(子节点除外) self:: 当前节点

XPath谓词(predicate)与函数(function)

[编辑]
有时为了进一步筛选,需要在XPath定位路径中使用谓词。通常一个定位路径的返回值是一个节点集。谓词是一个

小型表达式,可以对节点集中的节点进行判断。如果表达式判断的结果是“假”,那么就将该节点舍去。下面是一个 示例:

//p[@class=‘alert’]

上面的表达式对文档中的标签进行检验,判断它们的“class”属性是否为“alert”。只有那些满足这一条件的

标签才能够进入该定位路径所选出的节点集。

下面的示例则在谓词表达式中使用了一个函数来获取当前选择节点(也称为场景节点context node)的信息:


/book/chapter[position()=3]

结果是选择书中处于第三位的章节(chapter)。为了能够返回正确值,当前的<book>元素至少应该含有三个

<chapter>元素。同时请注意,函数position() 返回的是一个整数值。

XPath规范中有许多函数。想查看完整的函数列表,请阅读W3C规范。
以下是一些常用的函数:

数值型last() – 返回当前节点集中最后一个节点 数值型position() – 返回被测试的当前选择节点的位置 数值型count(node-set) – 返回节点集的节点数

布尔型starts-with(string, string) – 如果函数中前一个字符串参数的起始N个字符等于后一个字符串参数则返回真值 布尔型contains(string, string) – 如果函数中前一个字符串包含后一个字符串则返回真值 数值型sum(node-set) – 返回节点集中所有数值节点的数值总和 数值型floor(number) – 返回不超过其值的最大整数 数值型ceiling(number) – 返回不小于其值的最小整数 数值型round(number) – 返回四舍五入后的整数

练习

[编辑]
下面的练习可以提高您使用XPath的技巧。需要用到tree.xml文件和xsl-tree.xsl文件:
修改并复制xsl-tree.xsl文件,在复制后的文件名中加入相应题号。
  1. 找出thickness属性值为“thick”的bigBranch元素,打印其name属性值。
  2. 找出每个bigBranch的父节点,打印其name属性值。
  3. 找出带有color属性的leave节点,打印其color属性值。