2012-02-09 2 views
0

私はウェブページから主要なテキストコンテンツを抽出するいくつかのコードを書いてきました。有用な戦略の1つは、コンテンツの最初の段落を見つけ、pulol、または要素ではない次のすべての兄弟要素を選択することです。 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>')); 

私は多くの実験を行いましたが、最後のクエリの書き方を理解できませんでした。私は見つけることができました有効な見栄えの解決に最も近いがあるようなもの:タグpはないが、ul次の兄弟の位置を返すいくつかの表現である$EXPR

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

...、 ol、またはですが、そのような式がXPathで表現可能である場合、私はうまくいきませんでした。

XPathで説明した方法はありますか?

例:私はID first<p>要素への参照を持っている

<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> 
... 

は私の文書はこのようになりますと仮定します。私は、コンテンツノードとしてfirst要素を使用してXPath式の後にいます。これは、次の兄弟をParagraph 3、順序なしリスト、およびParagraph 4とします。 <hr>要素が私が望む要素(<p><ul><ol>、および<blockquote>)ではないため、その要素とその後のすべての兄弟要素は返されたノードセットの一部であってはなりません。 OPが説明したように

+0

冗長で混乱します。例としてシンプルなXMLを提供し、正確にどのノードを選択するかを示してください。これらのノードのそれぞれが満たすべきルールを説明してください。 –

+0

"p、ul、ol、またはblockquote要素ではない最初の要素を含むが、これを含まないすべての兄弟要素は冗長で混乱しますか? – Sean

+0

質問を編集してください - 多くの人がコメントを読むことはできません。 –

答えて

1

、彼が望んでいる:

次の兄弟のすべての要素まで、は含まない、AP、UL、OL、またはBLOCKQUOTE要素

ない 最初の1

I. XPath 1.0のソリューション:指名手配されている

ノードが2 nodesetsの交差点です。

  1. 'first'idpの兄弟を、次のされているすべての要素。

  2. hrの兄弟より前のすべての要素。

は、XPath 1.0でこれを見つけるために、我々は、ノードセットの交差点ためKayessian式を使用:上記のXPath式がノードセットの両方に属しているすべてのノードを選択します。

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

$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ない最初の要素を、A ulolまたはである。

その後、我々が交差したい2ノードセットが$vP1次のすべての兄弟と$vFirstNotInRangeの先行するすべての兄弟である:

は、私たちは$vFollowingP1で最初のノードセットを示すものと - これは、次のとおりです。

$vP1/following-sibling::* 

そして、私たちは$vPreceedingNotInRangeを有する第2ノードセットを表してみましょう - これは、次のとおりです。

$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::*) 
      ] 

この表現は正確に選択し、所望のノード。であるために補正し包ま - この変換は、以下のXML文書(設けられた非整形式XMLフラグメントに適用する場合

<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> 

:基づく検証 - ここ

はXSLTであります

<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> 

2つのXPath式(変数を1と置換すべての変数を持つ1)は、EVのとおりです。)WELLFORMED作ら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溶液:説明

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

:ここでは、XPath 2.0が "次" を使用

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

これも$vP1に従い、同じ所望のノードを選択している$vFirstNotInRangeの先行するいずれかの兄弟を選択します演算子>>

関連する問題