从xml中提取两个节点之间的节点

时间:2016-06-10 08:48:48

标签: xml xpath

我有一个xml文件:

<root>
<!-- all other kinds of xml elements including possibly other h1 -->

<dl> some text
  <dt>
    other text
  </dt>
</dl>
<!-- all other kinds of xml elements including possibly other h1 -->

<h1>
  <a>starting here</a>
</h1>

<dl>foo
  <dt>
    bar
  </dt>
</dl>
<dl>foo
  <dt>
    bar
  </dt>
</dl>

<!-- Many elements but all of them are dl -->

<dl>foo
  <dt>
    bar
  </dt>
</dl>
<dl>foo
  <dt>
    bar
  </dt>
</dl>

<h1>
  <a>Ending here</a>
</h1>

<!-- all other kinds of xml elements including possibly other h1 -->
<dl>foo
  <dt>
    bar
  </dt>
</dl>
<!-- all other kinds of xml elements including possibly other h1 -->

</root>

现在,我想在<dl>代码之间选择<h1>节点(及其子节点)。

我尝试了followingfollowing-sibling的各种组合,但没有成功。

任何人都可以帮助我吗?

4 个答案:

答案 0 :(得分:0)

您可以使用以下XPath 1.0表达式查找<dl>标记之间的<h1>节点:

//dl[preceding-sibling::*[1] = preceding-sibling::h1[1] and following-sibling::*[1] = following-sibling::h1[1]]

这会找到<dl>标记,其中前一个兄弟是<h1>标记,紧接着的兄弟标记也是<h1>标记。

根据要求,可以简化为:

//dl[preceding-sibling::h1 and following-sibling::h1]

只会在其之前或之后找到所有<dl>标记的<h1>标记。

请注意,您的XML需要包含一个根元素才能使其有效,并且您通常无法在无效的XML上执行XPath表达式。

答案 1 :(得分:0)

选择h1前面有h1

的所有dl标签
//h1/following-sibling::dl[following-sibling::h1]

答案 2 :(得分:0)

以前的答案都适用于具有两个h1标记的给定示例。 但是如果输入稍微复杂一点就行不通有三个或四个h1标签。

如果是这样,您可以遵循这个优秀的answer

以下是在第一个和第二个dl代码之间获取h1代码的修改

 //h1[1]/following-sibling::dl
      [count(.|//h1[2]/preceding-sibling::dl) = count(//h1[2]/preceding-sibling::dl)  ]

答案 3 :(得分:0)

由于相邻dl元素的序列必须紧跟h1兄弟之前和之后,因此选择所有dl元素序列的一个表达式为:

/*/dl[preceding-sibling::*[not(self::dl)][1][self::h1]
    and
      following-sibling::*[not(self::dl)][1][self::h1]
      ]

您可以使用以下表达式查找所有h1个元素,每个元素紧接在dl s的所需相邻序列之前:

/*/h1[following-sibling::*[1][self::dl]
    and
      following-sibling::*[not(self::dl)][1][self::h1]
     ]

您可以找到所有h1个元素,每个元素都紧跟在dl s的所需相邻序列之后,并带有以下表达式:

/*/h1[preceding-sibling::*[1][self::dl]
    and
      preceding-sibling::*[not(self::dl)][1][self::h1]
     ]

最后,这是一个基于XSLT的验证

此转换仅评估用于查找dl s的所有有序序列的表达式,并将它们复制到输出中。

它还会评估选择开始和结束h1的表达式,并输出结果。

最后,对于每对(起始h1,结束h1),它会计算一个XPath表达式,该表达式选择此特定组中的所有dl并输出结果。

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

  <xsl:template match="/">
    <xsl:copy-of select="
    /*/dl[preceding-sibling::*[not(self::dl)][1][self::h1]
        and
          following-sibling::*[not(self::dl)][1][self::h1]
         ]"/>
========================
<xsl:variable name="vStartingH1s" select=
 "/*/h1[following-sibling::*[1][self::dl]
       and
        following-sibling::*[not(self::dl)][1][self::h1]
        ]"/>

    <xsl:copy-of select="$vStartingH1s"/>
========================
    <xsl:variable name="vEndingH1s" select=
    "/*/h1[preceding-sibling::*[1][self::dl]
          and
           preceding-sibling::*[not(self::dl)][1][self::h1]
           ]"/>
    <xsl:copy-of select="$vEndingH1s"/>
========================
    <xsl:for-each select="$vStartingH1s">
      <xsl:variable name="vPos" select="position()"/>
      <xsl:value-of select=
          "concat(&#xA;'========== Group ', $vPos, ' ==========&#xA;')"/>
      <xsl:copy-of select=
      "following-sibling::*
            [count(.| $vEndingH1s[position()=$vPos]/preceding-sibling::*)
            =
             count($vEndingH1s[position()=$vPos]/preceding-sibling::*)
            ]"/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

将此转换应用于以下XML文档(提供的转换为包含两组想要的dl):

<root>
    <!-- all other kinds of xml elements including possibly other h1 -->
    <a/>
    <h1/>
    <dl> some text
        <dt>
        other text
        </dt>
    </dl>
    <!-- all other kinds of xml elements including possibly other h1 -->
    <b/>
    <h1/>
    <h1>
        <a>starting here</a>
    </h1>
    <dl>foo
        <dt>
        bar
        </dt>
    </dl>
    <dl>foo
        <dt>
        bar
        </dt>
    </dl>
    <!-- Many elements but all of them are dl -->
    <dl>foo
        <dt>
        bar
        </dt>
    </dl>
    <dl>foo
        <dt>
        bar
        </dt>
    </dl>
    <h1>
        <a>Ending here</a>
    </h1>
    <h1/>
    <c/>
    <h1/>
    <!-- all other kinds of xml elements including possibly other h1 -->
    <p/>
    <dl>foo
        <dt>
        bar
        </dt>
    </dl>
    <!-- all other kinds of xml elements including possibly other h1 -->
    <h1/>
    <d/>
    <h1>
        <a>starting here</a>
    </h1>
    <dl>foo
        <dt>
        bar
        </dt>
    </dl>
    <dl>foo
        <dt>
        bar
        </dt>
    </dl>
    <h1>
        <a>Ending here</a>
    </h1>
    <e/>
    <h1/>
<f/>

产生了想要的正确结果:

<dl>foo
        <dt>
        bar
        </dt>

</dl>
<dl>foo
        <dt>
        bar
        </dt>

</dl>
<dl>foo
        <dt>
        bar
        </dt>

</dl>
<dl>foo
        <dt>
        bar
        </dt>

</dl>
<dl>foo
        <dt>
        bar
        </dt>

</dl>
<dl>foo
        <dt>
        bar
        </dt>

</dl>
========================
<h1>

   <a>starting here</a>

</h1>
<h1>

   <a>starting here</a>

</h1>
========================
    <h1>

   <a>Ending here</a>

</h1>
<h1>

   <a>Ending here</a>

</h1>
========================
    ========== Group 1 ==========
<dl>foo
        <dt>
        bar
        </dt>

</dl>
<dl>foo
        <dt>
        bar
        </dt>

</dl>
<dl>foo
        <dt>
        bar
        </dt>

</dl>
<dl>foo
        <dt>
        bar
        </dt>

</dl>========== Group 2 ==========
<dl>foo
        <dt>
        bar
        </dt>

</dl>
<dl>foo
        <dt>
        bar
        </dt>

</dl>