代码之家  ›  专栏  ›  技术社区  ›  flybywire

xpath:获取没有x祖先的节点

  •  41
  • flybywire  · 技术社区  · 15 年前

    我希望XML文档的所有节点都不是节点X的后代。

    (我的实际问题有点复杂,但我现在仍然坚持“不是后代”这一部分)。

    2 回复  |  直到 8 年前
        1
  •  59
  •   jarnbjo    15 年前

    如果将“不是后代”转换为“没有祖先”,则得到表达式 //*[not(ancestor::X)] .这将返回文档中的所有节点,这些节点不是名为“x”的节点的后代。

        2
  •  18
  •   Robert Rossney    15 年前

    Jarnbjo指出了实现这一点的直观方法 //*[not(ancestor::X)] .这有一个非常大的优点,不管您的文档是如何构造的,它都会起作用,而且在大多数情况下您应该使用它。

    但是,如果您有一个非常大的文档,它可能会非常低效。这是一个非常昂贵的问题。它告诉xpath处理器访问文档中的每个节点,并检查其祖先节点是否存在名为x的元素。虽然xpath处理器足够智能,可以知道它不需要访问x的后代来评估该查询,但不太可能。

    如果您有一些关于x元素在哪里的信息,并且非常小心,那么您可以编写一个更有效的查询。例如,如果x是顶级元素的子元素,并且它有很多子元素,那么这将更快:

    /* | /*/* | /*/*[not(name()='X')]//*
    

    这将查找顶级元素、它的所有直接子元素以及它的任何未命名X的直接子元素的后代。它不会检查X的任何后代。

    同样,如果您知道x接近树的底部,则此查询可能更有效:

    //*[not(ancestor::*[position() <= 3][X])]
    

    因为它不会检查它测试的每个节点的整个祖先轴,只检查最后三个元素。(除非XPath处理器足够笨,在执行使用的测试时可以检查轴上的每个节点 position() 可能是这样。)

    不过,正如我所说,大多数时候,最简单的版本会是最好的,而大多数时候,它是我自己使用的。