如何使用XPath选择两个节点之间的所有元素

时间:2012-03-01 22:32:06

标签: c# c#-4.0 xpath

我如何在第1和第2 h2之间选择所有(所有可能的节点)?它们之间可以有 n 个节点,并且可以有 m h2标签。

节点不一定会包含在HTML元素中,因此选择器可以全部抓取它们。

<html>
 <h2>asdf</h2>
 <p>good stuff 1</p>
 <p>good stuff 2</p>
 <p>good <a href="#">asdf</a>stuff n...</p>
 <h2>qwer</h2>
 <p>test2</p>
 <h2>dfgh</h2>
 <p>test2</p>
</html>

我刚刚用XPath弄湿了脚。请帮助我的新手问题:)

非常感谢!

4 个答案:

答案 0 :(得分:4)

选择所需元素的一个XPath表达式是

   /*/h2[1]
      /following-sibling::p
        [count(. | /*/h2[2]/preceding-sibling::p)
        =
         count(/*/h2[2]/preceding-sibling::p)
        ]

一般情况下,在这种情况下,可以使用Kayessian公式进行集合交集:

$ns1[count(.|$ns2) = count($ns2)]

此XPath表达式选择属于的所有节点到节点集$ns1$ns2

如果要获取两个给定节点$ n1和$ n2之间的所有节点,则这是两个节点集的交集:$n1/following-sibling::node()$n2/preceding-sibling::node()

只需将这些表达式替换为Kayessian公式,您就拥有了想要的XPath表达式。

在XPath 2.0 中,当然可以使用<<>>运算符,例如:

 /*/h2[1]/following-sibling::p[. << /*/h2[1]/]

答案 1 :(得分:1)

不确定xpath,但你有一个标签C#4.0,所以下面的代码完成了这项工作:

XElement.Parse(xml)
                .Element("h2")
                .ElementsAfterSelf()
                .TakeWhile(n => n.Name != "h2")
                .ToList()

答案 2 :(得分:0)

这样的事情应该有效(不使用XPath)

  XmlReader reader = XmlReader.Create(new StringReader(xmlString));

  if (reader.ReadToDescendant("h2"))
  {
    reader.Skip();

    while (reader.Name != "h2")
    {        
      //Handle nodes
      reader.Read();
    }
  }

答案 3 :(得分:0)

我知道这不是一个有效的例子,但几乎就在那里,

您真正需要做的就是修复语法错误并修复递归项

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@* | node()">
    <xsl:call-template name="tmpMatchNode">
      <xsl:with-param name="indx" select="0"/>
      <xsl:with-param name="self" select="node()"/>
    </xsl:call-template>
  </xsl:template>
  <xsl:template name="tmpMatchNode" >
    <xsl:variable name="indx" />
    <xsl:variable name="self"/>

    <xsl:element name="name($self[index])">
      <xsl:value-of select="$self[$indx]"/>
    </xsl:element>
    <xsl:choose>
      <xsl:when test="$self[$indx+1]:name() != 'H2'">
        <xsl:call-template name="tmpMatchNode">
          <xsl:with-param name="indx" select="$indx +1"/>
          <xsl:with-param name="self" select="$self"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$self[$indx]:name() = 'H2'">
        <xsl:call-template name="tmpMatchNode">
          <xsl:with-param name="indx" select="$indx +1"/>
          <xsl:with-param name="self" select="$self"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:comment>DO NOTHING HERE AS WE HAVE NOTHING TO DO</xsl:comment>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>