本教程适用于JDK 8。本页面描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
请参阅Java语言更改了解Java SE 9及后续版本中更新的语言特性的概述。
请参阅JDK发行说明了解所有JDK发行版的新功能、增强功能和已删除或弃用选项的信息。
XPath规范是多种规范的基础,包括XSLT和链接/寻址规范,例如XPointer。因此,对XPath的理解对于许多高级XML用法至关重要。本节在XSLT的上下文中介绍XPath。
一般来说,XPath表达式指定了选择一组XML节点的模式。然后,XSLT模板在应用转换时使用这些模式。(另一方面,XPointer添加了定义“点”或“范围”的机制,以便可以使用XPath表达式进行寻址)。
XPath表达式中的节点不仅指元素,还包括文本和属性等其他内容。事实上,XPath规范定义了一个抽象的文档模型,其中定义了七种节点类型:
根节点
元素节点
文本节点
属性节点
注释节点
处理指令节点
命名空间节点
XML数据的根元素由一个元素节点模拟。XPath根节点包含文档的根元素以及与文档相关的其他信息。
与文档对象模型(DOM)类似,XSLT/XPath数据模型由包含各种节点的树组成。在给定的元素节点下,有文本节点、属性节点、元素节点、注释节点和处理指令节点。
在这个抽象模型中,语法上的区别消失了,你得到的是数据的规范化视图。例如,在文本节点中,无论文本是在CDATA部分中定义的还是包含实体引用,都没有区别。文本节点将包含规范化数据,即在所有解析完成后存在的数据。因此,文本将包含“<”字符,无论是否使用了实体引用(如“<”)或CDATA部分来包含它。(类似地,文本将包含“&”字符,无论是使用“&”还是在CDATA部分中使用它)。
在本节中,我们将主要处理元素节点和文本节点。其他寻址机制,请参阅XPath规范。
XSLT模板是应用于由XPath表达式选择的节点的一组格式化指令。在样式表中,XSLT模板可能如下所示:
<xsl:template match="//LIST"> ... </xsl:template>
表达式//LIST从输入流中选择了一组LIST节点。模板中的其他指令告诉系统如何处理它们。
由这样一个表达式选择的节点集合定义了模板中其他表达式求值的上下文。这个上下文可以被视为整个集合 - 例如,用于确定它包含的节点数。
上下文也可以被视为集合的一个成员,因为每个成员都是一个接一个地处理的。例如,在LIST处理模板内,表达式@type指的是当前LIST节点的type属性。(类似地,表达式@*指的是当前LIST元素的所有属性)。
XML文档是一个树形结构(分层)的节点集合。与层次化目录结构一样,指定一个指向层次结构中特定节点的路径(因此规范的名称是XPath)非常有用。实际上,大部分目录路径的表示法都保持不变:
斜杠(/)用作路径分隔符。
从文档根开始的绝对路径以/开头。
从给定位置开始的相对路径以其他字符开头。
双点(..)表示当前节点的父节点。
单点(.)表示当前节点。
例如,在可扩展HTML(XHTML)文档(一种看起来像HTML但符合XML规则的XML文档)中,路径/h1/h2/表示h1下的h2元素。(回想一下,在XML中,元素名区分大小写,因此这种规范在XHTML中比在普通HTML中效果更好,因为HTML是不区分大小写的)。
在与模式匹配规范(如XPath)中,规范/h1/h2选择所有位于h1元素下的h2元素。要选择特定的h2元素,可以使用方括号[]进行索引(类似于数组中使用的方括号)。因此,路径/h1[4]/h2[5]将选择第四个h1元素下的第五个h2元素。
注意 - 在XHTML中,所有元素名都是小写的。这是XML文档的一个非常常见的约定。然而,在像本教程这样的教程中,大写名字更容易阅读。因此,在接下来的XSLT课程中,所有XML元素名都将大写。(属性名,另一方面,将保持小写)。
XPath表达式中指定的名称是指一个元素。例如,在/h1/h2中的h1指的是一个h1元素。要引用一个属性,您需要用@符号前缀属性名。例如,@type指的是一个元素的type属性。假设您有一个带有LIST元素的XML文档,例如,表达式LIST/@type将选择LIST元素的type属性。
注意 - 因为表达式没有以/开头,所以该引用相对于当前上下文的列表节点 - 无论文档中的位置如何。
XPath表达式的完整范围利用了XPath定义的通配符、运算符和函数。您很快就会了解更多相关知识。这里,我们只介绍其中几个最常见的XPath表达式。
表达式@type="unordered"指定了一个名为type的属性,其值为unordered。类似LIST/@type的表达式指定了LIST元素的type属性。
您可以将这两种表示法结合起来得到一些有趣的结果。在XPath中,方括号表示法([])通常用于索引,但它也可以用来指定选择条件。因此,表达式LIST[@type="unordered"]选择所有type值为unordered的LIST元素。
类似的表达式也适用于元素。每个元素都有一个关联的字符串值,该值由连接元素下的所有文本段组成。(有关该过程的更详细解释,请参见元素的字符串值)。
假设您使用一个XML结构来建模组织中的活动,该结构由PROJECT元素和带有项目名称的文本字符串的ACTIVITY元素组成,还包括多个PERSON元素以列出相关人员,以及一个可选的STATUS元素来记录项目状态。以下是其他使用扩展的方括号表示法的示例:
/PROJECT[.="MyProject"]:选择名为"MyProject"的PROJECT。
/PROJECT[STATUS]:选择所有具有STATUS子元素的项目。
/PROJECT[STATUS="Critical"]:选择所有具有字符串值为Critical的STATUS子元素的项目。
XPath规范定义了相当多的地址机制,并且它们可以以许多不同的方式组合。因此,XPath在相对简单的规范中提供了很多表达能力。本节介绍了其他有趣的组合:
LIST[@type="ordered"][3]:选择所有类型为ordered的LIST元素,并返回第三个。
LIST[3][@type="ordered"]:选择第三个LIST元素,但仅当它的类型为ordered时。
注意:更多地址运算符的组合在XPath规范的2.5节中列出。这可能是定义XSLT转换的最有用的规范部分。
根据定义,一个未限定的XPath表达式选择与指定的模式匹配的一组XML节点。例如,/HEAD匹配所有顶级HEAD条目,而/HEAD[1]只匹配第一个。表 4-1列出了可以在XPath表达式中使用的通配符,以扩大模式匹配的范围。
表 4-1 XPath通配符
通配符 |
含义 |
---|---|
* |
匹配任何元素节点(不包括属性或文本)。 |
node() |
匹配任何类型的节点:元素节点、文本节点、属性节点、处理指令节点、命名空间节点或注释节点。 |
@* |
匹配任何属性节点。 |
在项目数据库示例中,/*/PERSON[.="Fred"]匹配任何以Fred命名的PROJECT或ACTIVITY元素。
到目前为止,你所见到的所有模式都指定了层级结构中的确切层级数。例如,/HEAD指定层级结构中第一级的任何HEAD元素,而/*/*指定层级结构中第二级的任何元素。要指定层级结构中的不确定层级,可以使用双斜杠(//)。例如,XPath表达式//PARA选择文档中的所有段落元素,无论它们在哪里找到。
模式//也可以在路径中使用。因此,表达式/HEAD/LIST//PARA表示从/HEAD/LIST开始的子树中的所有段落元素。
XPath表达式的结果可以是一组节点、一个字符串、一个布尔值(true/false),或一个数字。表 4-2列出了XPath表达式中可用的运算符:
表 4-2 XPath运算符
运算符 |
含义 |
---|---|
| |
选择。例如,PARA|LIST选择所有PARA和LIST元素。 |
or,and |
返回两个布尔值的或/与结果。 |
=,!= |
等于或不等于,适用于布尔值、字符串和数字。 |
<,>,<=,>= |
小于、大于、小于或等于、大于或等于,适用于数字。 |
+,-,*,div,mod |
加、减、乘、浮点除法和模(余数)运算(例如,6 mod 4 = 2)。 |
表达式可以用括号分组,这样你就不用担心运算符的优先级。
注意 - 运算符的优先级是回答这个问题的一个术语:“如果你指定 a + b * c,这是表示 (a+b) * c 还是 a + (b*c)?”(运算符的优先级与表中显示的大致相同)。
元素的字符串值是所有后代文本节点的连接,无论有多深。考虑下面的混合内容XML数据:
<PARA>This paragraph contains a <b>bold</b> word</PARA>
<PARA> 元素的字符串值是 This paragraph contains a bold word。特别要注意的是 <B> 是 <PARA> 的子元素,而文本 bold 是 <B> 的子元素。
重点是节点的所有子节点的文本都会连接起来形成字符串值。
此外,值得理解的是XPath定义的抽象数据模型中的文本是完全规范化的。所以无论XML结构中是否包含实体引用 < 或 < 在 CDATA 部分中,元素的字符串值都会包含 < 字符。因此,在使用XSLT样式表生成HTML或XML时,你必须将 < 的出现转换为 < 或将其置于 CDATA 部分中。类似地, & 的出现必须转换为 &。
本节结束时概述了XPath函数。你可以使用XPath函数以与你已经看到的元素规范相同的方式选择一组节点。其他函数返回一个字符串、一个数字或一个布尔值。例如,表达式 /PROJECT/text() 获取 PROJECT 节点的字符串值。
许多函数依赖于当前上下文。在上面的例子中,每次调用 text() 函数的上下文是当前选择的 PROJECT 节点。
有很多XPath函数 - 太多了,无法在这里详细描述。本节提供了一个简要的列表,显示了可用的XPath函数以及它们的功能摘要。有关函数的更多信息,请参阅XPath规范的第4节。
许多XPath表达式选择一组节点。实质上,它们返回一个节点集。一个函数也是如此。 id(...) 函数返回具有指定ID的节点(仅当文档有DTD时,元素才有ID,DTD指定了具有ID类型的属性)。
这些函数返回基于位置的数值。
last(): 返回最后一个元素的索引。例如,/HEAD[last()] 选择最后一个 HEAD 元素。
position(): 返回索引位置。例如,/HEAD[position() <= 5] 选择前五个 HEAD 元素。
count(...): 返回元素的数量。例如,/HEAD[count(HEAD)=0] 选择所有没有子标题的 HEAD 元素。
这些函数对字符串进行操作或返回字符串。
concat(string, string, ...): 连接字符串值。
starts-with(string1, string2): 如果 string1 以 string2 开头,则返回 true。
contains(string1, string2): 如果 string1 包含 string2,则返回 true。
substring-before(string1, string2): 返回 string1 中 string2 出现之前的部分。
substring-after(string1, string2): 返回 string1 中 string2 出现之后的部分。
substring(string, idx): 返回从索引位置到末尾的子字符串,其中第一个字符的索引为 1。
substring(string, idx, len): 返回从指定索引位置开始的指定长度的子字符串。
string-length(): 返回上下文节点的字符串值的大小;上下文节点是当前选择的节点-由应用了类似于 string-length() 的 XPath 表达式选择的节点。
string-length(string): 返回指定字符串的大小。
normalize-space(): 返回当前节点的规范化字符串值(没有前导或尾随空格,并且连续的空格字符转换为单个空格)。
normalize-space(string): 返回指定字符串的规范化字符串值。
translate(string1, string2, string3): 转换 string1,用 string2 中的字符替换 string1 中的对应字符。
注意 - XPath 定义了三种获取元素文本的方式:text()、string(object),以及在表达式中的元素名称暗示的字符串值,例如:/PROJECT[PERSON="Fred"]。
这些函数对布尔值进行操作或返回布尔值。
not(...): 对指定的布尔值取反。
true(): 返回 true。
false(): 返回 false。
lang(string): 如果上下文节点的语言(由 xml:Lang 属性指定)与指定的语言相同(或是其子语言),则返回 true;例如,Lang("en") 对于 <PARA_xml:Lang="en">...</PARA> 返回 true。
这些函数操作或返回数字值。
sum(...):返回指定节点集中每个节点的数值的总和。
floor(N):返回不大于N的最大整数。
ceiling(N):返回不小于N的最小整数。
round(N):返回最接近N的整数。
这些函数将一种数据类型转换为另一种数据类型。
string(...):返回数字、布尔值或节点集的字符串值。
boolean(...):返回数字、字符串或节点集的布尔值(非零数字、非空节点集和非空字符串都为真)。
number(...):返回布尔值、字符串或节点集的数值(true为1,false为0,包含数字的字符串变为该数字,节点集的字符串值被转换为数值)。
这些函数允许您确定节点的命名空间特性。
local-name():返回当前节点的名称,不包括命名空间前缀。
local-name(...):返回指定节点集中第一个节点的名称,不包括命名空间前缀。
namespace-uri():返回当前节点的命名空间 URI。
namespace-uri(...):返回指定节点集中第一个节点的命名空间 URI。
name():返回当前节点的扩展名称(URI 加上本地名称)。
name(...):返回指定节点集中第一个节点的扩展名称(URI 加上本地名称)。
XPath 运算符、函数、通配符和节点定位机制可以以多种方式组合使用。到目前为止,你所学到的内容应该能够帮助你为特定目的指定所需的模式。