【问题标题】:XPath for choosing a sibling after [closed][关闭] 之后选择同级的 XPath
【发布时间】:2012-09-08 21:07:47
【问题描述】:

我有以下 xml:

<root>
    <a>value1</a>
    <b>value2</b>
    <c>value3</c>
    <a>value5</a>
    <d>value4</d>
    <b>value2</b>
    <b>value3</b>
    <a>value7</a>
</root>

我想选择节点//b[text()='value2']之后的第一个兄弟a,如果它后面没有另一个b节点(在这种情况下它将是&lt;a&gt;value5&lt;/a&gt;,不应选择&lt;a&gt;value7&lt;/a&gt;)。

执行此操作的 xpath 是什么?

我正在使用 .net 4 和 xpath 1.0

更新

这就是我的出发点:我正在解析的文档有一个非常愚蠢的结构,可以这样描述

<root>
    <key>key-value</key>
    <some-other-nodes>some other values</some-other-nodes>
    <key>an other key value</key>
    <value>the value</value>
</root>

我描述的文档包含以下键值对: 键值->{null} 另一个键值->{该值}

如果键节点重复,它会重置key 值。我需要一个 xpath 来选择特定键的值。因为在上面的示例中,//b[text()='value2'] 的第二个匹配项后面跟着&lt;b&gt;value3&lt;/b&gt;,所以密钥被重置为value3

【问题讨论】:

  • 这里的主要问题是根据xml中标签的顺序编写代码。
  • ArsenZahray:你有两个&lt;b&gt;value2&lt;/b&gt; 元素——你必须更准确地说你想要其中的哪一个作为基础。 &lt;a&gt;value7&lt;/a&gt; 是正确答案,以防最初选择这些 b 中的第一个。
  • ArsenZahray:这个问题是矛盾的——&lt;a&gt;value5&lt;/a&gt; 后面跟着一个b——因此不能选择它——根据您的要求“我想选择第一个兄弟姐妹”节点//b[text()='value2'] 如果后面没有其他 b 节点”。请编辑并更正。
  • ArsenZahray:恕我直言,您的编辑令人费解——您希望它有什么意义吗?

标签: .net xml xpath


【解决方案1】:

使用

   //b[text()='value2']
          /following-sibling::b[last()]
                 /following-sibling::a[1]
  |
   //b[text()='value2']
        [not(following-sibling::b)]
             /following-sibling::a[1]

这会选择:

  1. 初始 b 元素的最后一个 b following-siblings 的第一个后续兄弟 a,或:

  2. 初始b元素的第一个后续兄弟,如果它没有任何其他后续兄弟b

这可以进一步简化为

  //b[text()='value2']/../b[last()]/following-sibling::a[1]

更新

由于//b[text()='value2'] 从提供的 XML 文档中选择 两个` 元素,OP 还必须在 XPath 表达式的第一个定位步骤中指定他希望选择这两个元素中的哪一个。 p>

这是一个更精确的 XPath 表达式,其中 $k 是在这种情况下所选元素 b[. = 'value2'] 的数字(1 或 2):

  (//b[text()='value2'])[$k]/../b[last()]/following-sibling::a[1]

基于 XSLT 的验证

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:param name="k" select="1"/>

 <xsl:template match="/">
  <xsl:copy-of select=
  "(//b[text()='value2'])[$k]
      /../b[last()]
         /following-sibling::a[1]"/>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<root>
    <a>value1</a>
    <b>value2</b>
    <c>value3</c>
    <a>value5</a>
    <d>value4</d>
    <b>value2</b>
    <b>value3</b>
    <a>value7</a>
</root>

对 XPath 表达式求值,并将通过该求值选择的元素复制到输出中

<a>value7</a>

【讨论】:

  • 在 firepath 中测试,这会选择 &lt;a&gt;value7&lt;/a&gt; 而不会选择 &lt;a&gt;value5&lt;/a&gt;,这与我需要的相反
  • @ArsenZahray:你有 两个 &lt;b&gt;value2&lt;/b&gt; 元素——你必须更准确地确定你想要哪个作为基础。 &lt;a&gt;value7&lt;/a&gt; 如果最初选择了这些b中的第一个,则正确答案。
【解决方案2】:

这是一个应该可以工作的:

//b[.='value2']/following-sibling::a[preceding-sibling::b[1][.='value2']]

简单地说,它选择任何b 元素之后的a 元素,其值为'value2',其中最近的b 元素的值为'value2'

编辑:现在我想一想,我什至不确定你是否需要第一部分。试试这个:

//a[preceding-sibling::b[1][.='value2']]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    • 2013-11-17
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 2017-04-13
    • 2016-03-16
    相关资源
    最近更新 更多