【问题标题】:XPath - All following siblings except first specific elementsXPath - 除了第一个特定元素之外的所有后续兄弟
【发布时间】:2011-05-17 02:16:15
【问题描述】:

假设我正在查询一个 xhtml 文档,并且我想查询带有 id='target' 的表后面的所有兄弟姐妹。此外,我既不想要这个特定元素的第一个 <table> 同级,也不想要第一个 <ol> 同级。这是我能想到的最好的:

//table[@id='target']/following-sibling::*[not(self::table[1]) and not(self::ol[1])]

但是,这并没有在应该返回任何结果的时候返回。显然我不理解其中的一些语法(我找不到好的信息来源)。如果在 XPath 语法方面更有经验的人可以帮助我,我当然会很感激。另外,出于纯粹的学术目的,我很好奇上述内容实际上在做什么。

更新:
请参阅 LarsH 的回答以了解为什么我的 XPath 无法正常工作,并参阅 Dimitre 的回答以了解已接受的解决方案。

【问题讨论】:

  • 好问题,+1。请参阅我对一个 XPath 表达式的回答,该表达式准确地选择了想要的节点。 :)

标签: xml xhtml xpath


【解决方案1】:

使用

 /table[@id='target']/following-sibling::*[not(self::table) and not(self::ol)] 
| 
 /table[@id='target']/following-sibling::table[position() > 1]
|
 /table[@id='target']/following-sibling::ol[position() > 1]

这将选择表的所有以下非table 和非ol 的兄弟姐妹,以及以下所有位置为2 或更高的table 兄弟姐妹以及所有以下ol 位置为2 或更高的兄弟姐妹.

这正是您想要的:除了第一个 table 跟随兄弟姐妹和第一个 ol 跟随兄弟姐妹之外的所有后续兄弟姐妹。

这是纯 XPath 1.0,不使用任何 XSLT 函数。

【讨论】:

  • 这正是我一直在寻找的优雅解决方案,而且它实际上非常简单。我从来没有想过要得到三个互斥集合的并集,其中包含除了这两个元素之外的所有内容。谢谢!
  • 啊,应该好好想想。 :-) 我正在尝试联合解决方案,但无法得到它。拼写错误:根据原始问题,table 之前需要 // 而不是 /
  • 嘿,出于某种原因,我认为联合解决方案会很糟糕,因此特别避免使用它。 +1 因为不像我那样愚蠢。 :-)
【解决方案2】:

首先回答第二个问题:上面所做的是选择所有以下既不是table也不是ol元素的兄弟。

原因如下:self::table[1] 选择上下文节点的 self(如果它通过了 table 元素名称测试)并过滤以仅选择 self:: 轴上的第一个节点。 self:: 轴上最多有一个节点通过元素名称测试,因此[1] 是多余的。 self::table[1] 只要上下文节点是表元素,就会选择它,而不管它在其兄弟节点中的位置如何。所以not(self::table[1]) 在上下文节点是表元素时返回 false,无论它在兄弟节点中的位置如何。

self::ol[1] 也是如此。

如何做你想做的事: @John Kugelman 的回答几乎是正确的,但忽略了我们必须在 table[@id='target'] 之前(包括 table[@id='target'])之前忽略兄弟元素的事实。我认为在纯 XPath 1.0 中无法正确执行。 您有可能使用 XPath 2.0 吗?如果您在浏览器中工作,答案通常是否定的。

一些解决方法是:

  • 通过在某些其他基础上(例如它们的属性)进行过滤,跳过下表的第一个同级和第一个 ol 同级;
  • 选择//table[@id='target']作为节点集,将其返回到宿主环境(即在XPath之外,例如在JavaScript中),循环通过该节点集;循环内部:通过 XPath 选择 following-sibling::*,在 XPath 之外遍历 that,并测试每个结果(在 XPath 之外),看它是第一个表还是 ol。
  • 选择//table[@id='target']作为节点集,将其返回到宿主环境(即在XPath之外,例如在JavaScript中),循环通过该节点集;在循环内部:通过 XPath 选择 generate-id(following-sibling::table[1])generate-id(following-sibling::ol[1]),将这些值接收到 JS 变量 t1id 和 o1id,并使用 'following-sibling::*[generate-id() != ' + t1id + ' and generate-id() != ' + o1id + ']' 的形式为 XPath 表达式构造一个字符串。在 XPath 中选择该字符串,您就有了答案! :-p

更新:在 XSLT 1.0 中可能的解决方案 - 请参阅 @Dimitre's。

【讨论】:

  • @John Kugelman:看看我的回答,了解一个纯粹且不太复杂的 XPath 1.0 解决方案。
  • 感谢您对我尝试查询失败的原因进行了很好的解释。我最终选择了 Dimitre 的 XPath 来解决这个问题。
【解决方案3】:

当你使用self:: 轴时,只会有一个节点,所以我相信self::*[1] 永远是正确的。每个节点都将成为其自己的self:: 轴上的第一个(也是唯一一个)节点。这意味着您的括号表达式等效于[not(self::table) and not(self::ol)],这意味着所有表格和列表都被过滤掉了。

我没有设置测试环境,但我想这可能会更好:

/table[@id='target']/following-sibling::*
    [not(self::table and not(preceding-sibling::table)) and
     not(self::ol    and not(preceding-sibling::ol))]

它需要一些调整,但想法是过滤掉没有前置兄弟tables 的tables 和没有前置兄弟ols 的ols。

【讨论】:

  • 正如我在回答中指出的那样,此解决方案忽略了这样一个事实,即当您测试以下兄弟姐妹以查看哪个是 [1] 时,目标表不应算作前兄弟姐妹。此外,目标表之前的任何表或ol元素都必须被前置兄弟测试忽略。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-22
  • 1970-01-01
  • 2012-07-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多