2012-02-09 42 views
0

我一直在寫一些代碼,從網頁中提取主要的文本內容。一個有用的策略是找到第一段內容,然後選擇所有以下兄弟元素,但不包括第一個不是p,ul,ol或元素的兄弟元素。在Perl,代碼看起來是這樣的:是否可以截斷給定節點上的XPath軸?

my ($firstpara) = $document->findnodes('//p[whatever]'); 
my @content = ($firstpara); 
for my $sibling ($firstpara->findnodes('following-sibling::*')) { 
    last if $sibling->tag !~ /^(?:p|ol|ul|blockquote)\z/; 
    push @content, $sibling; 
} 

這是不是太糟糕,但它會很酷,能夠得到我想要只使用XPath的節點,所以我可以寫這樣的事情,而不是:

my ($firstpara) = $document->findnodes('//p[whatever]'); 
my @content = ($firstpara, $firstpara->findnodes('<query>')); 

我已經做了很多實驗,但一直未能弄清楚如何編寫最後一個查詢。最近的一個有效的尋找的解決方案,我已經能夠找到的是一樣的東西:

$firstpara->findnodes('following-sibling::*[position() < $EXPR]'); 

...其中$EXPR是一些表達式返回一個同級的其標記爲不pul的位置, ol或,但是我一直無法弄清楚如果這樣的表達式在XPath中是可以表達的。

有什麼辦法可以做到我在XPath中描述的內容?

例子:

假設我的文件看起來是這樣的:

<h1>Header</h1> 
<p>Paragraph 1</p> 
<p id="first">Paragraph 2</p> 
<p>Paragraph 3</p> 
<ul><li>Item 1</li><li>Item 2</li></ul> 
<p>Paragraph 4</p> 
<hr> 
<p>Paragraph 5</p> 
<blockquote>Blockquote 1</blockquote> 
... 

我有ID first一個參考<p>元素。我在XPath表達式之後,使用該元素作爲內容節點,這將給我以下兄弟姐妹Paragraph 3,無序列表和Paragraph 4<hr>元素不在我想要的那些元素之中(<p>,<ul>,<ol><blockquote>),以便元素及其後的所有同級元素不應該成爲返回節點集的一部分。

+0

冗長而混亂。請提供一個簡單的XML作爲示例,並指出您要選擇哪些節點 - 解釋每個節點必須滿足的規則。 「 – 2012-02-10 14:12:29

+0

」以下所有的兄弟元素,但不包括第一個不是p,ul,ol或blockquote元素的兄弟元素「是冗長而混亂的? – Sean 2012-02-11 21:00:54

+0

請編輯問題 - 沒有多少人會閱讀評論。 – 2012-02-12 00:06:33

回答

1

由於OP解釋,他想:

以下所有兄弟元素最多,但不包括,這不是AP,UL,OL,或BLOCKQUOTE元素

的 第一個

I.的XPath 1.0溶液:

所希望的節點是兩個節點集的交集:

  1. 被繼pid的兄弟姐妹值'first'所有元素。

  2. 所有在hr之前的兄弟姐妹的元素。

要使用XPath 1.0找到此我們使用Kayessian公式節點集相交

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

以上的XPath表達式選擇屬於同時向節點集的所有節點$ns1到節點集$ns2

$vP1定義爲/*/p[@id='first']

$vFirstNotInRange是:

$vP1/following-sibling::* 
    [not(self::p or self::ul 
     or self::ol or self::blockquote) 
    ] [1] 

此選擇第一不需要的節點(在此情況下hr),或更精確地:那就是$vP1一個下列同屬和這不是一個p第一元件,一個ulol或。

然後,我們要交兩個節點集都是下面的$vP1兄弟姐妹的$vFirstNotInRange所有前面的兄弟姐妹:

讓我們$vFollowingP1表示第一個節點集合 - 這就是:

$vP1/following-sibling::* 

讓我們與$vPreceedingNotInRange表示第二節點集合 - 這就是:

$vFirstNotInRange/preceding-sibling::* 

最後,我們在Kayessina公式$ns1中用$vPreceedingNotInRange$ns2替換爲$vFollowingP1。這些替代的reult準確選擇想要的節點:

$vPreceedingNotInRange 
     [count(.|$vFollowingP1) 
     = 
      count($vFollowingP1) 
     ] 

如果我們替換所有的變量,直到我們得到一個不包含任何變量的表達式,我們得到:

/*/p[@id='first']/following-sibling::* 
    [not(self::p or self::ul 
     or self::ol or self::blockquote 
     ) 
    ] [1] 
     /preceding-sibling::* 
      [count(.| /*/p[@id='first']/following-sibling::*) 
      = 
      count(/*/p[@id='first']/following-sibling::*) 
      ] 

這種表達準確選擇想要的節點。

下面是一個XSLT - 基於驗證

<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:variable name="vP1" select="/*/p[@id='first']"/> 

<xsl:variable name="vFirstNotInRange" select= 
    "$vP1/following-sibling::* 
    [not(self::p or self::ul 
     or self::ol or self::blockquote) 
    ] [1]"/> 

<xsl:variable name="vFollowingP1" 
     select="$vP1/following-sibling::*"/> 

<xsl:variable name="vPreceedingNotInRange" 
     select="$vFirstNotInRange/preceding-sibling::*"/> 

<xsl:template match="/"> 
    <xsl:copy-of select= 
    "$vPreceedingNotInRange 
    [count(.|$vFollowingP1) 
    = 
    count($vFollowingP1) 
    ]"/> 
================ 

    <xsl:copy-of select= 
    "/*/p[@id='first']/following-sibling::* 
    [not(self::p or self::ul 
     or self::ol or self::blockquote 
     ) 
    ] [1] 
     /preceding-sibling::* 
      [count(.| /*/p[@id='first']/following-sibling::*) 
      = 
      count(/*/p[@id='first']/following-sibling::*) 
      ] 

    "/> 
</xsl:template> 
</xsl:stylesheet> 

當施加這種轉變在下面的XML文檔(所提供的非簡潔(wellformed)XML片段 - 校正,並且包裹在爲了造簡潔(wellformed)):

<html> 
    <h1>Header</h1> 
    <p>Paragraph 1</p> 
    <p id="first">Paragraph 2</p> 
    <p>Paragraph 3</p> 
    <ul> 
     <li>Item 1</li> 
     <li>Item 2</li> 
    </ul> 
    <p>Paragraph 4</p> 
    <hr/> 
    <p>Paragraph 5</p> 
    <blockquote>Blockquote 1</blockquote> 
</html> 

兩個XPath表達式(一個變量和一個與取代的所有變量)是EV aluated和想要的,正確的選擇的節點輸出

<p>Paragraph 3</p> 
<ul> 
    <li>Item 1</li> 
    <li>Item 2</li> 
</ul> 
<p>Paragraph 4</p> 
================ 

    <p>Paragraph 3</p> 
<ul> 
    <li>Item 1</li> 
    <li>Item 2</li> 
</ul> 
<p>Paragraph 4</p> 

II。 XPath 2。0溶液

$vFirstNotInRange/preceding-sibling::* 
           [. >> $vP1] 

這將選擇的$vFirstNotInRange前述任一兄弟,其也下列$vP1和選擇相同的通緝節點:

<p>Paragraph 3</p> 
<ul> 
    <li>Item 1</li> 
    <li>Item 2</li> 
</ul> 
<p>Paragraph 4</p> 

說明:在這裏,我們使用XPath 2.0 「跟隨」運營商>>

相關問題