XML/XPath
XPath
编辑学习目标
编辑完成本章的学习后,您将能够:
- 形成这样的概念:一个XML文档是一棵节点树
- 在XML文档中引用元素组
- 了解简写与非简写XPath语法的不同
- 了解绝对路径与相对路径的不同
- 使用XPath谓词和函数提炼出一个XPath节点集
概述
编辑- 在前面的章节中您已经学习了XSL。进行XSL转换时基本上都必须引用XML文档中的节点。目前常使用一种简单易懂
的语法来引用XML文档中的节点。这种语法就是XPath。当然XPath具有更多我们尚未利用的特征和能力。本章将深 入介绍XPath这种XML的路径语言,常用于引用XML文档中的节点。
- 本章将对XPath语法进行简要的概括,但这足以使您了解它的基本概念。想全面地深入认识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 |
<?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>节点的父节点。(注意本例是相对于 <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 |
<?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定位路径。当您在朋友面前这样谈论事物时,会显得您的思路十分有条理:
- 简写的相对定位路径
- 简写的绝对定位路径
- 未简写的相对定位路径
- 未简写的绝对定位路径
- 此处仅列出了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文件,在复制后的文件名中加入相应题号。
- 找出thickness属性值为“thick”的bigBranch元素,打印其name属性值。
- 找出每个bigBranch的父节点,打印其name属性值。
- 找出带有color属性的leave节点,打印其color属性值。