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

C# 如何使用XPath选择两个节点之间的所有元素,c#,c#-4.0,xpath,C#,C# 4.0,Xpath,如何选择第一个和第二个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...&l

如何选择第一个和第二个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>

asdf
好东西1

好东西2

好东西

qwer 测试2

dfgh 测试2

我只是被XPath弄湿了脚。请帮助我的新手提问:)


非常感谢

不确定xpath,但您有一个标记C#4.0,因此以下代码可以完成这项工作:

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

类似的东西应该可以工作(但不使用XPath)


选择所需元素的一个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/后面的同级::node()
$n2/前面的同级::node()

只要将这些表达式替换为Kayessian公式,就得到了所需的XPath表达式

在XPath 2.0中,当然可以使用
操作符,类似于:

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

/*/h2[1]/following sibling::p[.我知道这不是一个有效的示例,但它几乎已经存在了

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

<?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>

我们无事可做,在这里什么也不做

为什么?至少感谢您指出我答案中的错误:我没有很好地阅读示例XML以了解发生了什么。是否可以用星号替换p以获取h2s之间的所有内容,即使它们不在p标记中@DimitreNovatchev@Hoppe,是,执行此操作将选择所有图元(不是“一切”:)在两个节点之间。你能停止用诸如“我的答案对你有用吗?”?"关于他们的问题。这只是噪音,我们正因为他们不断地清理旗帜。如果你的答案是好的,它将吸引更多的选票并被接受。你现在应该很清楚这一点。谢谢。@Kev:你能不能停止干扰我与人之间的交流?将此添加到你删除的有用的、投票率较高的答案和评论中sal,这让你成为一个很好的主持人。
<?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>