我没有找到一种明确的方法来选择HTML文件中两个 anchor 之间的所有节点(<a></a>标记对)。

第一个 anchor 具有以下格式:

<a href="file://START..."></a>

第二 anchor :
<a href="file://END..."></a>

我已经验证了可以使用-来选择两者(请注意,我使用的是HTML Agility Pack):
HtmlNode n0 = html.DocumentNode.SelectSingleNode("//a[starts-with(@href,'file://START')]"));
HtmlNode n1 = html.DocumentNode.SelectSingleNode("//a[starts-with(@href,'file://END')]"));

考虑到这一点,以及我业余的XPath技能,我编写了以下表达式来获取两个 anchor 之间的所有标记:
html.DocumentNode.SelectNodes("//*[not(following-sibling::a[starts-with(@href,'file://START0')]) and not (preceding-sibling::a[starts-with(@href,'file://END0')])]");

这似乎可行,但是会选择所有HTML文档!

我需要例如以下HTML片段:
<html>
...

<a href="file://START0"></a>
<p>First nodes</p>
<p>First nodes
    <span>X</span>
</p>
<p>First nodes</p>
<a href="file://END0"></a>

...
</html>

删除两个 anchor ,三个P(当然包括内部SPAN)。

有什么办法吗?

我不知道XPath 2.0是否提供更好的方法来实现这一目标。

* 编辑(特殊情况!)*

我还应该处理以下情况:

“在X和X'之间选择标签,其中X是<p><a href="file://..."></a></p>

因此,而不是:
<a href="file://START..."></a>
<!-- xhtml to be extracted -->
<a href="file://END..."></a>

我还应该处理:
<p>
  <a href="file://START..."></a>
</p>
<!-- xhtml to be extracted -->

<p>
  <a href="file://END..."></a>
</p>

再一次非常感谢你。

最佳答案

使用此XPath 1.0表达式:

//a[starts-with(@href,'file://START')]/following-sibling::node()
     [count(.| //a[starts-with(@href,'file://END')]/preceding-sibling::node())
     =
      count(//a[starts-with(@href,'file://END')]/preceding-sibling::node())
     ]

或者,使用此XPath 2.0表达式:
    //a[starts-with(@href,'file://START')]/following-sibling::node()
  intersect
    //a[starts-with(@href,'file://END')]/preceding-sibling::node()

XPath 2.0表达式使用XPath 2.0 intersect运算符。

XPath 1.0表达式将Kayessian(在@Michael Kay之后)公式用于两个节点集的相交:
$ns1[count(.|$ns2) = count($ns2)]

使用XSLT进行验证:

此XSLT 1.0转换:
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  <xsl:copy-of select=
  "    //a[starts-with(@href,'file://START')]/following-sibling::node()
         [count(.| //a[starts-with(@href,'file://END')]/preceding-sibling::node())
         =
          count(//a[starts-with(@href,'file://END')]/preceding-sibling::node())
         ]
  "/>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档时:
<html>...
    <a href="file://START0"></a>
    <p>First nodes</p>
    <p>First nodes
        <span>X</span>
    </p>
    <p>First nodes</p>
    <a href="file://END0"></a>...
</html>

产生所需的正确结果:
<p>First nodes</p>
<p>First nodes
        <span>X</span>
</p>
<p>First nodes</p>

此XSLT 2.0转换:
<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  <xsl:copy-of select=
  " //a[starts-with(@href,'file://START')]/following-sibling::node()
   intersect
    //a[starts-with(@href,'file://END')]/preceding-sibling::node()
  "/>
 </xsl:template>
</xsl:stylesheet>

应用于相同的XML文档(如上)时,将再次精确地生成所需的结果

关于html - XPath表达式: Select elements between A HREF ="expr" tags,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6554261/

10-08 21:49
查看更多