XPath 2.0有一些新的函数和语法,相对于1.0,可以使用序列。其中一些并没有真正增加语言在1.0中的功能(使用节点集),但它们更容易以更具可读性的方式表达所需的逻辑。这增加了程序员获得正确代码的机会 - 并保持这种方式。例如,
empty(s)
相当于not(s)
,但是当您想测试序列是否为空时,它的意图会更清晰。
empty((0))
!= not((0))
。这也适用于布尔上下文中的exists(s)
与s
。但是,有s
个域empty(s)
等同于not(s)
,因此这两个域可以在这些域中互换使用。但这表明使用empty()
可以在使代码更易于理解方面起到重要作用。exists(s)
相当于已经存在于XPath 1.0中的boolean(s)
(或者在布尔上下文中只是s
),但对于意图再次更加清晰。some $x in
表达 satisfies
测试 ($x)
"等同于boolean(
表达式 [
test (.)])
(虽然新语法更灵活,因为你不会#39 ; t需要担心丢失上下文项,因为你有变量来引用它。)every $x in
表达 satisfies
测试 ($x)
"等同于not(
表达式 [not(
test (.))])
,但更具可读性。这些功能和语法显然是以不小的代价添加的,仅仅是为了实现编写更容易映射到人类思考方式的XPath的目标。正如经验丰富的开发人员所知,这意味着可理解的代码明显优于难以理解的代码。
考虑到所有......编写一个要求
的XPath测试表达式的清晰可读方式值X是否按顺序S?
出现
一些方法:(注意:我在这里用X
和S
表示法来表示值和序列,但我并不是要暗示这些子表达式是元素名称测试,也不是简单的表达。它们可能很复杂。)
X = S
:这将是最不可读的之一,因为它需要读者
index-of(S, X)
:这个清楚地说明了什么是作为一个值的意图以及作为一个序列的内容(如果你还记得index-of()
的参数顺序)。但它表达的不仅仅是我们需要:它要求索引,当我们真正想知道的是是否 X出现在S中。这对读者来说有点误导。经验丰富的开发人员将通过一些努力和对上下文的理解来弄清楚他们的目的是什么。但是我们越依赖于上下文来理解每一行的意图,就越能理解代码变成循环(螺旋)和潜在的Sisyphean任务!此外,由于index-of()
旨在返回X的所有出现索引的列表,因此可能比必要的更昂贵:智能处理器,为了评估X = S
,不会必须要找到S的所有内容,也不必按顺序列举它们;但是对于index-of(S, X)
,必须确定正确的顺序,并且必须将S的所有内容与X进行比较。使用index-of()
的另一个缺点是它仅限于使用{{1用于比较;例如,您无法使用它来询问节点是否与给定序列中的任何节点相同。
eq
。 (但至少我们不会得到错误的布尔值,因为Effective boolean value is not defined for a sequence of two or more items starting with a numeric value
不能返回零。)如果S可以有多个X实例,那么这是另一个有理由更喜欢表格3或6。index-of()
:使意图更清晰,如果处理器足够智能,可以帮助处理器消除性能损失。exists(index-of(X, S))
:这个很清楚,完全符合我们的意图。与1相比似乎啰嗦,这本身就会降低可读性。但为了清晰起见,这可能是可接受的价格。请记住,X和S本身可能是复杂的表达式 - 它们不一定只是变量引用。一个优点是,由于some $m in S satisfies $m eq X
运算符是显式的,您可以将其替换为eq
或任何其他比较运算符。is
:比1清楚,但是分享2的语义缺点:它计算S的所有等于X的成员。实际上,这可能会返回假阴性(不正确的有效布尔值),如果X是假的。例如。即使S[. eq X]
中出现(0, 1)[. eq 0]
,0
也会返回0.这是假的。(0, 1)
:比1,2,3和5更清晰。不如4清楚,但更短。避免5(或至少大部分,取决于处理器智能)的缺点。我有点倾向于最后一个,此时:exists(S[. eq X])
你呢......作为一个开发人员来到一个复杂的,不熟悉的XSLT或XQuery或其他使用XPath 2.0的程序,想要弄清楚该程序正在做什么,你会发现哪个最容易阅读?
为长期问题道歉。感谢您阅读此内容。
修改:在上述讨论中,我尽可能将exists(S[. eq X])
更改为=
,以便更轻松地查看"值比较" (与一般比较相反)是有意的。
答案 0 :(得分:3)
对于它的价值,如果名称或上下文清楚地表明X是单身,我很乐意使用你的第一个表格,X = S - 例如当我想要检查一个可能的一组属性值时值:
<xsl:when test="@type = ('A', 'A+', 'A-', 'B+')" />
或
<xsl:when test="@type = $magic-types"/>
如果我认为存在混淆的风险,那么我喜欢你的第六种表述。我不太经常记住计算有效布尔值的规则,我犯错误的频率就越低。
答案 1 :(得分:2)
我更喜欢这个:
count(distinct-values($seq)) eq count(distinct-values(($x, $seq)))
当$ x本身是一个序列时,此表达式实现两组值之间关系的(基于值)子集,表示为序列。 子集的这种实现只具有线性时间复杂度 - 与许多其他表达方式相比,具有O(N ^ 2)时间复杂度。
总结,单个值是否属于一组值的问题是一个问题的特殊情况,即 set 是否为值是另一个的子集。如果我们对后者有很好的实施,我们可以简单地用它来回答前者。
答案 2 :(得分:2)
functx library有一个很好的实现这个功能,所以你可以使用
functx:is-node-in-sequence($X, $Y)
(此特定功能可在http://www.xqueryfunctions.com/xq/functx_is-node-in-sequence.html)
找到整个functx库可用于XQuery(http://www.xqueryfunctions.com/)和XSLT(http://www.xsltfunctions.com/)
Marklogic将functx库与其核心产品一起发布;其他供应商也可能。
答案 3 :(得分:0)
当你想知道序列S中是否出现节点 X时,另一种可能性是
exists((X) intersect S)
我认为这很可读,简洁。但它只适用于X和S中的值是节点;如果你试着问
exists(('bob') intersect ('alice', 'bob'))
您将收到运行时错误。 在我现在正在处理的程序中,我需要比较字符串,所以这不是一个选项。
正如迪米特里指出的那样,序列中节点的出现是一个身份问题,而不是价值比较问题。