2010-02-17 99 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>