【问题标题】:How to select all nodes with the same name for different parent nodes?如何为不同的父节点选择所有同名节点?
【发布时间】:2011-10-20 08:57:34
【问题描述】:

假设我有以下 xml:

<root>
  <person>
    <name>John</name>
  </person>
  <children>
    <person>
      <name>Jack</name>
    </person>
  </children>
</root>

是否可以同时选择两个人?假设我不知道另一个人在孩子标签中,他们很容易在配偶标签或完全不同的东西中,并且可能在另一个孩子中。我知道我需要的所有人都在根标签中(不一定是文档根)。

【问题讨论】:

  • @_Thijs Wouters:您接受了错误的答案。 @nonnb 的答案是正确的。

标签: xml xslt xpath


【解决方案1】:

你可以使用

//person

//*[local-name()='person']

要在文档中查找任何 person 元素,但要小心 - 某些 xsl 处理器(如 Microsoft 的),双斜杠的性能在大型 xml 文档上可能很差,因为需要评估文档中的所有节点.

编辑:
如果您知道“人”只有 2 条路径,那么您可以完全避免使用 //

<xsl:for-each select="/root/person | /root/children/person">
    <outputPerson>
        <xsl:value-of select="name/text()" />
    </outputPerson>
</xsl:for-each>

或命名空间不可知:

<xsl:for-each select="/*[local-name()='root']/*[local-name()='person'] 
  | /*[local-name()='root']/*[local-name()='children']/*[local-name()='person']">

【讨论】:

  • +1,有用的建议。不过,我会提醒您:performance of double slash is poor on large xml documents,它取决于 XSLT/XPath 处理器。这是一个非常常见的操作,一个好的处理器会按元素名称构建索引以使其非常快。
  • P.S.我假设name 是指您要查找的元素的名称,即person。 OP 实际上并不是在寻找名为 name 的元素。
  • @Lars - 感谢反馈 - outputPerson 只是为了给 OP 一个例子 - 他没有给出输出 xml 模式。我在 BizTalk 2009 Maps 中使用 // 的体验很糟糕 - 处理文档 ~100MB 会导致 CPU 使用率飙升。在我的情况下,我只是懒惰 - 用完整路径替换 // 避免了这个问题,'no //' 现在是我们 BizTalk 地图的编码标准。
  • 我的一些从事 XQuery 内部工作的朋友告诉我,曾经有一段时间 // 对于包括他们的引擎在内的许多引擎来说都很慢,而显式路径则更快。现在他们已经改变了他们的内部表示,他们中的一些人告诉我,情况正好相反,他们希望 // 应该避免的想法没有传播得如此广泛。因此,性能铁律仍然适用:如果对您很重要,请在运行 your 处理器的 your 数据上测量 your 替代解决方案,并采取所有一般规则,即使来自消息灵通的人,也是有趣的民间传说。
  • @C.M.Sperberg-McQueen 谢谢 - 我将来会听取您的建议并获得相应的资格。
【解决方案2】:

在 Petar Ivanov 的回答中,// 的定义是错误的

以下是 XPath 1.0 W3C Specification 中的正确定义:

///descendant-or-self::node()/ 的缩写

【讨论】:

    【解决方案3】:
    //name
    

    将匹配两者,无论它们在 xml 树中的什么位置。

    //从当前节点中选择文档中匹配选择的节点,无论它们在哪里(link

    【讨论】:

    • @Petre:始终仅提供来自规范来源的任何定义。在您的回答中,XPath 伪运算符 // 的“定义”是错误的。
    • w3schools 因此类垃圾而臭名昭著。表中出现此定义的两个“表达式”甚至不是表达式。而且这个定义没有意义。
    • 此外,OP 要求 person 元素,而不是 name 元素。很遗憾这个答案被接受了。
    【解决方案4】:

    或者你可以使用:

    root//人

    所以你只在根元素中搜索 persion

    【讨论】:

      【解决方案5】:

      正如 nonnb 所说,双斜杠在大型 xml 文档上的性能很差。

      所以//name 可以解决问题,但可能会带来更多您期望的元素。 另外想象一下,在您的根元素中,您有一些不是人的元素,这些元素可能具有名为 name 的后代元素,根据您不想提出的问题,//name 将提出他们起来。

      您应该将您的上下文节点仿射为最大值,以便在性能方面您的 XPath 将是最佳的。

      对于这个精确的文档,我会使用

      /root/descendant::person/name
      

      希望对你有帮助,

      【讨论】:

      • descendant:: 的性能并不比// 好。事实上// 只是/descendant-or-self::node()/ 的缩写。所以你提议的表达式等同于/root//person/name
      • 但我不是至少没有装人吗?我知道它不会有太大变化,但在语法上感觉更准确——据我说。
      • 不确定你在问什么。如果您要问/root//person/name 的性能是否优于/root//person,这似乎不太可能:处理器必须首先找到所有person 元素从/root 继承,然后找到每个人的子name 元素。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多