XPath运算符无需转义,直接使用+、-、*、=、and、or等;但在XML属性中需对、&等字符进行XML实体转义,如、&;字符串引号冲突时用单双引号互避,或concat()函数拼接。

XPath的运算符本身,在XPath表达式内部使用时,通常不需要“转义”。它们是语言的组成部分,直接书写即可,比如
+、
-、
*、
=、
and、
or等等。但如果你的XPath表达式字符串本身被嵌入到其他语言环境(例如XML属性值、编程语言的字符串常量)中,那么这些外部语言的规则可能会要求你对XPath字符串中的特定字符进行转义,这与XPath运算符本身无关,而是外部语言的语法要求。真正的挑战往往出现在字符串字面量中的引号处理,以及当XPath表达式作为XML属性值时对XML特殊字符的转义。
解决方案
我们在写XPath的时候,直观上会觉得某些符号是不是得特别处理一下,尤其当你从其他编程语言的背景看过来。但对于XPath的核心运算符,比如加减乘除、逻辑判断(
and,
or,
not)、比较运算符(
=,
!=,
<,
>,
<=,
>=),它们就是直接用的。你写
price > 10,那个
>就是
>,不需要写成
\>或者别的什么。
真正的“陷阱”或者说需要“变通”的地方,主要集中在两个方面:
-
XPath字符串字面量中的引号处理:这是最常见的问题。如果你想在XPath中匹配一个包含引号的字符串,比如
"It's a test"
,你就不能简单地用单引号包围它,因为字符串内部的单引号会提前结束你的字符串。XPath本身没有像大多数编程语言那样的反斜杠转义机制(例如\'
或\"
)。它的解决方式是:- 如果你的字符串内容包含单引号(
'
),就用双引号("
)来包围整个字符串。例如://item[text()="It's a great day"]
。 - 如果你的字符串内容包含双引号(
"
),就用单引号('
)来包围整个字符串。例如://item[text()='He said "Hello!"']
。 - 如果你的字符串内容既包含单引号又包含双引号,或者你需要匹配的字符串正好是当前字符串定界符的类型,那就需要使用
concat()
函数来拼接字符串。这是XPath 1.0时代最常用的策略,虽然有点啰嗦,但非常可靠。例如,要匹配字符串It's "really" good
,你可以这样写:concat('It', "'", 's "really" good')。
- 如果你的字符串内容包含单引号(
-
XPath表达式作为XML/HTML属性值时的XML实体转义:当你把一个XPath表达式放在XML或HTML标签的属性里时,比如在一个XSLT样式表的
select
属性中,XML解析器会先处理这个属性值。XML有它自己的特殊字符,例如<
、>
、&
、"
、'
。如果你的XPath表达式中包含了这些字符,它们必须按照XML的规则进行实体转义,否则XML解析会报错。zuojiankuohaophpcn
代替<
(小于号)youjiankuohaophpcn
代替>
(大于号)&
代替&
(和号)"
代替"
(双引号,当属性值用双引号包围时,如果内容也需要双引号)'
代替'
(单引号,当属性值用单引号包围时,如果内容也需要单引号) 最常见的是比较运算符>
和<
。比如,select="a[@id < 10]"
在XML属性中就是错误的,必须写成select="a[@id zuojiankuohaophpcn 10]"
。
理解这两点,基本就能解决XPath中所有关于“转义”的困惑了。
XPath字符串中引号的处理方法
处理XPath字符串中的引号,其实就是个“避让”的策略,而不是传统意义上的字符转义。我个人觉得,这地方是很多初学者最容易卡壳的地方,因为大家习惯了编程语言里用反斜杠
\来转义的模式。但XPath它就是这么设计的,简单粗暴但有效。
当你需要匹配的文本内容本身包含引号时,你得灵活选择用来包围整个字符串的引号类型。 比如,你有一个XML节点,其文本内容是
It's a beautiful day!。如果你想匹配它,你不能写
//someNode[text()='It's a beautiful day!']。因为第一个单引号后面的
s会让XPath认为字符串已经结束了,然后
s就成了语法错误。这时候,你得用双引号来包围整个字符串:
//someNode[text()="It's a beautiful day!"]。
反过来也一样。如果文本内容是
He said "Hello!",你就得用单引号:
//anotherNode[text()='He said "Hello!"']。
那如果文本内容是
It's "really" good!呢?既有单引号又有双引号,这时候就没法简单地用一种引号来包围了。这正是
concat()函数大显身手的时候。
concat()函数可以接受任意数量的参数,并将它们连接成一个字符串。所以,你可以把字符串拆分成几部分,然后用
concat()拼接起来。 例如:
//item[text()=concat('It', "'", 's "really" good!')]。这里,'是一个包含单引号的字符串,
's "really" good!'是另一个。这样,XPath就能正确解析你的意图了。这种方法虽然看起来有点笨拙,但它在XPath 1.0中是处理复杂字符串字面量的标准且唯一的方式。
XPath表达式在XML属性中如何书写?
当我们将XPath表达式嵌入到XML或HTML文档的属性值中时,比如在XSLT的
或者
web.xml配置文件的某个XPath表达式,就必须遵守XML的属性值规则。这意味着,任何在XPath表达式中出现的XML保留字符(
<,
>,
&,
",
')都必须被替换为它们对应的XML实体。
这是一个非常常见的错误点,因为XPath本身可能没问题,但XML解析器会先对整个文档进行解析。比如,你想选择所有
id小于10的元素:
//element[@id < 10]。如果你直接把这个放到XML属性里,比如
select="//element[@id < 10]",XML解析器一看到
<就会认为这是标签的开始,然后报错。所以,你必须将其转义为
zuojiankuohaophpcn:
select="//element[@id zuojiankuohaophpcn 10]"
同理,大于号
>需要写成
youjiankuohaophpcn。逻辑与
and操作符的
&符号也需要转义成
&,尽管XPath中更常用的是直接写
and这个关键字,而不是
&符号。 例如,一个更复杂的例子:
select="items/item[price youjiankuohaophpcn 100 and @category='electronics']"这里,
>被转义了,而
@category='electronics'中的单引号因为属性值是双引号包围的,所以不需要额外转义。但如果你的XPath字符串内部需要双引号,并且你的XML属性也是用双引号包围的,那么内部的双引号就得用
"来表示。例如:
select='items/item[@description="He said "Hello""]'(注意这里XML属性本身用单引号包围,所以XPath字符串内部的双引号需要转义)。
总而言之,记住一点:当XPath表达式成为XML属性值的一部分时,它首先是一个XML属性值,然后才是一个XPath表达式。所以,XML的语法规则优先级更高。
XPath运算符的优先级与括号使用
XPath中的运算符,就像大多数编程语言一样,有它们固定的优先级规则。理解这些优先级对于编写复杂且行为正确的XPath表达式至关重要,否则你可能会得到意想不到的结果。这不是“转义”的问题,而是确保表达式按照你的意图被计算的问题。
比如,数学运算符的优先级通常是乘除高于加减。在XPath中也是如此。
1 + 2 * 3结果是
7(先算
2 * 3 = 6,再加
1) 如果你想要先执行加法,再执行乘法,就必须使用括号
()来明确指定运算顺序。
(1 + 2) * 3结果是
9(先算
1 + 2 = 3,再乘
3)
逻辑运算符也有优先级。
and通常比
or的优先级高。
//item[category='book' and price > 50 or stock < 10]这个表达式的实际含义是:
//item[(category='book' and price > 50) or stock < 10]它会先判断
category='book' and price > 50这个条件,然后将结果与
stock < 10进行或运算。这意味着,即使
category不是
book且
price不高,只要
stock < 10,这个
item也会被选中。
如果你希望的是:
//item[category='book' and (price > 50 or stock < 10)]也就是,必须是
book类别,并且满足价格大于50 或者 库存小于10这两个条件中的一个。这时候,括号就是不可或缺的,它能强制XPath按照你期望的逻辑顺序进行计算。
所以,当你的XPath表达式变得复杂,涉及到多个运算符和条件时,不要吝啬使用括号。括号不仅能确保表达式的正确性,也能大大提高表达式的可读性,让其他人(包括未来的你自己)更容易理解你的意图。这是一种良好的编程习惯,在XPath中同样适用。










