XPath 中最可读的方式是编写“值 X 是序列 S 的成员吗”?

Lar*_*rsH 5 coding-style xpath-2.0

相对于 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以便更容易地看到“值比较”(而不是一般比较)的意图。

C. *_*een 5

就其价值而言,如果名称或上下文明确表明 X 是单例,我很乐意使用您的第一种形式 X = S ——例如,当我想根据一组可能值检查属性值时:

<xsl:when test="@type = ('A', 'A+', 'A-', 'B+')" />
Run Code Online (Sandbox Code Playgroud)

或者

<xsl:when test="@type = $magic-types"/>
Run Code Online (Sandbox Code Playgroud)

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


Dim*_*hev 2

我更喜欢这个

count(distinct-values($seq)) eq count(distinct-values(($x, $seq)))
Run Code Online (Sandbox Code Playgroud)

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

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