【问题标题】:Select first result in XPath在 XPath 中选择第一个结果
【发布时间】:2013-12-20 11:51:37
【问题描述】:

我看过这个问题:Select first instance only with XPath?

但如果我有这样的节点集:


<container value="">
  <data id="1"></data>
  <data id="2">test</data>
  <container>
    <data id="1">test</data>
    <data id="3">test</data>
  </container>
</container>

现在我的情况是这个节点集在文档的深处,我有一个指向内部容器的指针。所以我必须在我的 XPath 前面加上“/container/container”(路径实际上更长,但对于这个例子来说应该这样做)。

编辑: 我想要的是一个 id 为 1 的“数据”节点,它应该首先来自最低节点或最近的祖先。所以,如果我在“当前”(/container/container)上找不到它,我应该看看祖先并找到最近的一个(或者最后,什么都找不到)。我试过这个:

/container/container/ancestor-or-self::container/data[@id="1"]

这会带回一个包含两个节点的结果集。我想我可以使用 last() 来获得最深的,所以我在最后加上了它,但无济于事。

【问题讨论】:

  • 规范可以做得更清楚。你想要数据节点吗?数据节点的 id 必须为 1?如果数据节点的 id 不为 1,则形成原始容器,您想将文档向上移动到父容器,以查看是否有 id 为 1 的数据节点,如果没有,则一直持续到具有 id 的数据节点1 个被发现。是这样描述的吗?
  • 我试图更清楚地描述我正在寻找的东西,尽管有些人猜到了。对不起!

标签: xpath


【解决方案1】:

确保last() 的范围正确。试试:

(/container/container/ancestor-or-self::container/data[@id="1"])[last()]

同样:

//container[last()]

和:

(//container)[last()]

不是一回事。第一个将返回层次结构每个级别的最后一个容器节点 - 多个匹配项 - 第二个将返回找到的最后一个容器节点 - 一个匹配项。

【讨论】:

  • 实际上,我发现在匹配数据元素之前指定子容器节点的情况下,这不起作用。
  • @Nick Spacek - 我改进了下面的答案,现在它甚至涵盖了那个极端情况
【解决方案2】:

你是如何尝试使用 last() 的?我认为这应该可行:

/container/container/ancestor-or-self::container/data[@id="1"][last()]

编辑:

对,当然,我忘了括号:

(/container/container/ancestor-or-self::container/data[@id="1"])[last()]

这使得这与其他答案之一相同;但是,正如原始海报指出的那样,此表达式在以下情况下失败:

<container value="">
  <container>
    <data id="1">a3</data>
    <data id="3">a4</data>
  </container>
  <data id="1">a1</data>
  <data id="2">a2</data>
</container>

忠于 stackoverflow 的精神,但我可以将我的答案与其他答案之一结合起来,得到适用于所有情况的答案:

(/container/container/ancestor-or-self::container[data[@id="1"]])[last()]/data[@id="1"]

顺便说一句,如果一个容器有多个@id-is-1 子级,这将返回所有子级。只返回第一个这样的 元素:

(/container/container/ancestor-or-self::container[data[@id="1"]])[last()]/data[@id="1"][1]

【讨论】:

  • 如果我在此处阅读的所需结果是正确的(如果大),这将不起作用,因为 last() 将在祖先或自我的两个分支上匹配 - 这是真正的问题,所以您需要提前(如我所做的那样)或晚(如 Dave 所做的那样)剪辑结果集。
  • 这个可以。非常感谢(大家)!
【解决方案3】:

我不是 100% 清楚你的要求,但如果我没看错,也许你只是想要:

/container/container/ancestor-or-self::container[1]/data[@id='1']

注意“[1]”

编辑:再考虑一下,以下对我来说适用于到目前为止寻找@id=$N的所有情况

/container/container/ancestor-or-self::container[data[@id=$N]][1]/data[@id=$N]

非常极端的 xpathing 就在那里。基本上发生的事情是来自祖先或自我的节点集在位置 1 返回最低顺序 - 这就是你想要的 - 但你需要在它上面放置第二个条件,该节点也有一个你感兴趣的数据节点,一旦满足了这些条件,您就拥有了正确的节点,您现在只想进一步挖掘实际数据。

如果您将 xpath 拆开并将其视为一种算法,则 99% 的时间会变得更容易 :)

【讨论】:

  • 我试过了,但这并不能涵盖所有情况。如果我正在寻找 @id='2' 怎么办?我想在祖先之前支持当前节点的结果,但能够回退。
【解决方案4】:

试试 [位置()=1]

例如

/container/container/ancestor-or-self::container/data[position()=1]

【讨论】:

    【解决方案5】:

    代替

    @id="1"
    

    你试过了吗:

    position() == 1
    

    【讨论】:

    • 如果 position() == 1 可以工作,那么只需将祖先或自我:: 放在一起。我认为要求不仅针对任何第一个数据节点,还针对 id 为 1 的数据节点。问题并不像它可能的那样清楚。
    猜你喜欢
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    • 2011-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多