4

相对于 1.0,XPath 2.0 有一些新的函数和语法,可以处理序列。其中一些集合并没有真正添加到语言在 1.0 中已经可以做的事情(使用节点集合),但它们使以更易读的方式表达所需的逻辑变得更容易。这增加了程序员获得正确代码并保持这种方式的机会。例如,

  • empty(s)等价于not(s),但是当你想测试一个序列是否为空时,它的意图要清楚得多。
    • 更正:序列的有效布尔值通常比这更复杂。例如empty((0))!= not((0))。这也适用于布尔上下文中的exists(s)vs .。s但是,有些域swhereempty(s)等价于not(s),因此两者可以在这些域中互换使用。但这表明使用empty()可以在使代码更易于理解方面产生不小的差异。
  • 类似地,exists(s)等效boolean(s)于 XPath 1.0 中已经存在的内容(或只是s在布尔上下文中),但其意图更加清晰。
  • 量化表达式;例如,“some $x in 表达式 satisfies 测试($x)”将等同于boolean(表达式[测试(.)])(尽管新语法更灵活,因为您不必担心丢失上下文项,因为您有引用它的变量)。
  • 类似地,“every $x in 表达式 satisfies 测试($x)”将等同于not(表达式[not(测试(.))]),但更具可读性。

显然,这些函数和语法的添加成本不低,只是为了实现编写更容易映射到人类思维方式的 XPath 的目标。正如经验丰富的开发人员所知,这意味着可理解的代码明显优于难以理解的代码。

鉴于所有这些......编写一个询问的 XPath 测试表达式的清晰易读的方法是什么

值 X 是否出现在序列 S 中?

一些方法:(注意:我在这里使用XS符号来表示值和序列,但我并不是暗示这些子表达式是元素名称测试,也不是简单的表达式。它们可能很复杂。 )

  1. X = S: 这将是最难读的之一,因为它要求读者
    • 考虑 X 和 S 中的哪一个是序列与单个值
    • 理解一般比较,从语法上看不明显
      1. 然而,这种形式的一个优点是它允许我们将主题(X) 放在评论之前(“是 S 的成员”),我认为这有助于提高可读性。
      2. 另请参阅CMS关于可读性的好点,当语法或名称使 X 和 S 的“基数”显而易见时。
  2. index-of(S, X):这个很清楚什么是值和序列(如果你记得参数的顺序index-of())。但它表达的超出了我们的需要:它要求索引,而我们真正想知道的只是X是否出现在 S 中。这对读者有点误导。有经验的开发人员会通过一些努力和对上下文的理解来弄清楚它的意图。但是我们越是依赖上下文来理解每一行的意图,就越能理解代码变成一个循环(螺旋)和潜在的西西弗斯任务!此外,由于index-of()旨在返回 X 出现的所有索引的列表,它可能比必要的更昂贵:智能处理器,为了评估X = S,不一定要找到 S 的所有内容,也不一定要按顺序枚举它们;但是对于index-of(S, X),必须确定正确的顺序,并且必须将 S 的所有内容与 X 进行比较。使用的另一个缺点index-of()是它仅限于eq用于比较;例如,您不能用它来询问一个节点是否给定序列中的任何节点相同。
    • 更正:此表格用作条件测试,可能会导致运行时错误:Effective boolean value is not defined for a sequence of two or more items starting with a numeric value. (但至少我们不会得到错误的布尔值,因为index-of()不能返回零。)如果 S 可以有多个 X 实例,这是另一个选择形式 3 或 6 的好理由。
  3. exists(index-of(X, S)):使意图更清晰,如果处理器足够智能,将有助于处理器消除性能损失。
  4. some $m in S satisfies $m eq X: 这个很清楚,完全符合我们的意图。与 1 相比,它似乎冗长,而且它本身会降低可读性。但为了清楚起见,这可能是一个可以接受的价格。请记住,X 和 S 本身可能是复杂的表达式——它们不一定只是变量引用。一个优点是,由于eq运算符是显式的,您可以将其替换为is或任何其他比较运算符。
  5. S[. eq X]:比 1 更清晰,但具有 2 的语义缺陷:它计算 S 中等于 X 的所有成员。实际上,如果 X 为假,这可能会返回假阴性(不正确的有效布尔值)。例如(0, 1)[. eq 0],返回 0 这是虚假的,即使0发生在(0, 1).
  6. exists(S[. eq X]):比 1、2、3、5 更清晰。不如 4 清晰,但更短。避免 5 的缺点(或至少其中大部分,取决于处理器的智能)。

在这一点上,我有点倾向于最后一个:exists(S[. eq X])

那么您呢... 作为一名开发人员,他正在处理一个复杂的、不熟悉的 XSLT 或 XQuery 或其他使用 XPath 2.0 的程序,并想弄清楚该程序在做什么,您认为哪个最容易阅读?

为长长的问题道歉。感谢您阅读本文。

编辑:我在上面的讨论中尽可能地改变了,以便更容易看到“价值比较”(而不是一般比较)的意图=eq

4

4 回答 4

4

对于它的价值,如果名称或上下文清楚地表明 X 是单例,我很乐意使用您的第一种形式 X = S - 例如,当我想根据一组可能的值检查属性值时:

<xsl:when test="@type = ('A', 'A+', 'A-', 'B+')" />

或者

<xsl:when test="@type = $magic-types"/>

如果我认为存在混淆的风险,那么我喜欢你的第六种表述。我必须记住计算有效布尔值的规则的频率越低,我犯错误的频率就越少。

于 2013-06-22T18:16:24.593 回答
2

functx有一个很好的实现这个函数,所以你可以使用

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 库与他们的核心产品一起提供;其他供应商也可能。

于 2013-03-15T18:24:52.880 回答
2

我更喜欢这个

count(distinct-values($seq)) eq count(distinct-values(($x, $seq)))

当 $x 本身是一个序列时,这个表达式实现了两组值之间的(基于值的)关系子集,它们表示为序列。子集的这种实现只有线性时间复杂度 - 与许多其他表达方式相比,它们具有 O(N^2)) 时间复杂度。

总而言之单个值是否属于一组值的问题是一组值是否是另一值的子集的一个特例。如果我们对后者有很好的实现,我们可以简单地用它来回答前者。

于 2013-03-15T04:13:11.307 回答
0

另一种可能性,当您想知道节点X 是否出现在序列 S 中时,是

exists((X) intersect S)

我认为这非常易读,简洁。但它仅在 X 和 S 中的值是节点时才有效;如果你试着问

exists(('bob') intersect ('alice', 'bob'))

你会得到一个运行时错误。在我现在正在处理的程序中,我需要比较字符串,所以这不是一个选项。

正如 Dimitri 所指出的,序列中节点的出现是一个身份问题,而不是价值比较问题。

于 2013-03-15T21:09:55.580 回答