2010-02-17 96 views
3

我试图选择元素(a)与XPath 1.0(或可能与正则表达式),它们跟随特定元素(b)的同胞,但仅在另一个b元素之前。XPath“之后的兄弟姐妹”

<img><b>First</b><br>&nbsp;&nbsp; 
<img>&nbsp;&nbsp;<a href="/first-href">First Href</a> - 19:30<br> 
<img><b>Second</b><br>&nbsp;&nbsp; 
<img>&nbsp;&nbsp;<a href="/second-href">Second Href</a> - 19:30<br> 
<img>&nbsp;&nbsp;<a href="/third-href">Third Href</a> - 19:30<br> 

我试着让样本尽可能接近现实世界。因此,在这种情况下,当我在元素

<b>First</b> 

,我需要选择

<a href="/first-href">First Href</a> 

,当我在

<b>Second</b> 

,我需要选择

<a href="/second-href">Second Href</a> 
<a href="/third-href">Third Href</a> 

任何想法如何实现?谢谢!

+0

我们可以假设xml格式正确吗?br''元素实际上是'
'?此外'img'元素有内容并以'/>'结尾?如果“真实世界”包含格式良好的XML(如果不是XPath不是一种选择),它确实会有所帮助。 – AnthonyWJones 2010-02-17 12:54:25

+0

作为真实世界的例子,当然它不是很好的形成。我希望它是:(但是,我使用Html Agility Pack(.NET)来处理标记,并且它容忍格式不正确的文档,如果有任何帮助的话。 – 2010-02-17 13:14:49

+0

没有理由认为“真实世界”意味着mal -xml。有很多html提供的例子以及XML格式。当然,你提到的敏捷性问题会让情景变得更加清晰,增加适当的标签。 – AnthonyWJones 2010-02-17 18:42:13

回答

5

动态创建这个XPath:

following-sibling::a[preceding-sibling::b[1][.='xxxx']] 

其中 'xxxx' 是替换当前<b>的文本。

这是假设所有元素实际上都是兄弟姐妹。如果不是,您可以尝试使用precedingfollowing轴,或者编写更类似于文档结构的更具体的XPath。

在XSLT你也可以使用:

following-sibling::a[ 
    generate-id(preceding-sibling::b[1]) = generate-id(current()) 
] 
1

这里是一个解决方案,它只是一个单一的XPath表达式

使用的Kaysian公式两个节点集$ns1$ns2的交集

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

我们可以替换为$ns1与遵循当前<b>节点<a>兄弟节点集,我们用节点集替代$ns2<a>之前的兄弟姐妹在下一个<b>节点。

下面是一个使用一个完整的变换此

<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:apply-templates select="*/b"/> 
    </xsl:template> 

    <xsl:template match="b"> 
    At: <xsl:value-of select="."/> 

    <xsl:variable name="vNextB" select="following-sibling::b[1]"/> 

    <xsl:variable name="vA-sAfterCurrentB" select="following-sibling::a"/> 

    <xsl:variable name="vA-sBeforeNextB" select= 
    "$vNextB/preceding-sibling::a 
    | 
    $vA-sAfterCurrentB[not($vNextB)] 
    "/> 

    <xsl:copy-of select= 
    "$vA-sAfterCurrentB 
       [count(.| $vA-sBeforeNextB) 
       = 
       count($vA-sBeforeNextB) 
       ] 
    "/> 
    </xsl:template> 
</xsl:stylesheet> 

当在下面的XML文档施加这种转变:

<t> 
    <img/> 
    <b>First</b> 
    <br />&#xA0;&#xA0; 
    <img/>&#xA0;&#xA0; 
    <a href="/first-href">First Href</a> - 19:30 
    <br /> 
    <img/> 
    <b>Second</b> 
    <br /> 
    <img/>&#xA0;&#xA0; 
    <a href="/second-href">Second Href</a> - 19:30 
    <br /> 
    <img/>&#xA0; 
    <a href="/third-href">Third Href</a> - 19:30 
    <br /> 
</t> 

正确的结果产生

At: First <a href="/first-href">First Href</a> 
    At: Second <a href="/second-href">Second Href</a> 
<a href="/third-href">Third Href</a>