XPath表达式:选择A HREF ="expr"标记之间的元素

Her*_*nán 5 html tags select xpath

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

第一个锚具有以下格式:

<a href="file://START..."></a>
Run Code Online (Sandbox Code Playgroud)

第二锚:

<a href="file://END..."></a>
Run Code Online (Sandbox Code Playgroud)

我已经验证了可以使用starts-with选择两者(请注意我使用的是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')]"));
Run Code Online (Sandbox Code Playgroud)

考虑到这一点,以及我的业余XPath技能,我编写了以下表达式来获取两个锚点之间的所有标记:

html.DocumentNode.SelectNodes("//*[not(following-sibling::a[starts-with(@href,'file://START0')]) and not (preceding-sibling::a[starts-with(@href,'file://END0')])]");
Run Code Online (Sandbox Code Playgroud)

这似乎工作,但选择所有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>
Run Code Online (Sandbox Code Playgroud)

删除两个锚点,三个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>
Run Code Online (Sandbox Code Playgroud)

我也应该处理:

<p>
  <a href="file://START..."></a>
</p>
<!-- xhtml to be extracted -->

<p>
  <a href="file://END..."></a>
</p>
Run Code Online (Sandbox Code Playgroud)

再一次非常感谢你.

Dim*_*hev 6

使用此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())
     ]
Run Code Online (Sandbox Code Playgroud)

或者,使用此XPath 2.0表达式:

    //a[starts-with(@href,'file://START')]/following-sibling::node()
  intersect
    //a[starts-with(@href,'file://END')]/preceding-sibling::node()
Run Code Online (Sandbox Code Playgroud)

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

XPath 1.0表达式使用Kayessian(在@Michael Kay之后)公式用于两个节点集的交叉连接:

$ns1[count(.|$ns2) = count($ns2)]
Run Code Online (Sandbox Code Playgroud)

使用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>
Run Code Online (Sandbox Code Playgroud)

当应用于提供的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>
Run Code Online (Sandbox Code Playgroud)

产生想要的,正确的结果:

<p>First nodes</p>
<p>First nodes    
        <span>X</span>
</p>
<p>First nodes</p>
Run Code Online (Sandbox Code Playgroud)

这个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>
Run Code Online (Sandbox Code Playgroud)

当应用于同一XML文档(上面)时,再次产生完全想要的结果.