2009-11-04 5 views
8

TagSoupを使用してXMLSlurperに整形式構造体を渡すHTMLパーサーを作成しています。XmlSlurperの使い方:GPathResultの繰り返し処理中にサブ要素を選択する方法

ここでは一般的なコードです:

def htmlText = """ 
<html> 
<body> 
<div id="divId" class="divclass"> 
<h2>Heading 2</h2> 
<ol> 
<li><h3><a class="box" href="#href1">href1 link text</a> <span>extra stuff</span></h3><address>Here is the address<span>Telephone number: <strong>telephone</strong></span></address></li> 
<li><h3><a class="box" href="#href2">href2 link text</a> <span>extra stuff</span></h3><address>Here is another address<span>Another telephone: <strong>0845 1111111</strong></span></address></li> 
</ol> 
</div> 
</body> 
</html> 
"""  

def html = new XmlSlurper(new org.ccil.cowan.tagsoup.Parser()).parseText(htmlText); 

html.'**'.grep { [email protected] == 'divclass' }.ol.li.each { linkItem -> 
    def link = [email protected] 
    def address = linkItem.address.text() 
    println "$link: $address\n" 
} 

は、私は、各Iは、対応するHREFと住所の詳細を取得することができますので、私は順番に各「李」を選択させることを期待します。代わりに、私はこの出力を取得しています:

#href1#href2: Here is the addressTelephone number: telephoneHere is another addressAnother telephone: 0845 1111111 

私は、ウェブ上のさまざまな例をチェックしましたし、これらは、いずれかのXMLを扱う、または「このファイルからのすべてのリンクを取得する」のようなワンライナーの例です。 it.h3.a. @ href式は親の 'li'ノードへの参照を渡していても、テキスト内のすべてのhrefを収集しているようです。

あなたは私が知っていることができます:

私は各「李」アイテム

感謝のHREF /アドレスのペアを取得することができますどのよう

  • 示す出力を得ているのはなぜ
  • 答えて

    11

    のfindとgrepを置き換えます。

    html.'**'.find { [email protected] == 'divclass' }.ol.li.each { linkItem -> 
        def link = [email protected] 
        def address = linkItem.address.text() 
        println "$link: $address\n" 
    } 
    

    、あなたは

    #href1: Here is the addressTelephone number: telephone 
    
    #href2: Here is another addressAnother telephone: 0845 1111111 
    

    のgrepはArrayListのを返し得るが、戻りNodeChildクラス見つけることができます:に

    println html.'**'.grep { [email protected] == 'divclass' }.getClass() 
    println html.'**'.find { [email protected] == 'divclass' }.getClass() 
    

    結果を:

    class java.util.ArrayList 
    class groovy.util.slurpersupport.NodeChild 
    
    あなたはグレップを使用したい場合は

    ので、あなたはその後、巣そのため、このような別のそれぞれは、あなたのケースでは、

    html.'**'.grep { [email protected] == 'divclass' }.ol.li.each { 
        it.each { linkItem -> 
         def link = [email protected] 
         def address = linkItem.address.text() 
         println "$link: $address\n" 
        } 
    } 
    

    かいつまんを仕事というよりも、grepを見つける使用することができます。

    +0

    優秀な回答! –

    1

    これは難しい問題でした。 class = 'divclass'の要素が1つだけの場合、前の回答は正常です。 grepから複数の結果があった場合、単一の結果に対するfind()は答えではありません。結果がArrayListであることを指摘してください。外側ネストされた.each()ループを挿入すると、クロージャパラメータdivにGPathResultが提供されます。ここからドリルダウンは期待どおりの結果を続けることができます。

    html."**".grep { [email protected] == 'divclass' }.each { div -> div.ol.li.each { linkItem -> 
        def link = [email protected] 
        def address = linkItem.address.text() 
        println "$link: $address\n" 
    }} 
    

    元のコードの動作は、もう少し説明を使用することもできます。 GroovyのList上でプロパティにアクセスすると、リスト内の各要素のプロパティで新しいリスト(同じサイズ)を取得します。 grep()が見つけたリストには1つのエントリしかありません。次に、プロパティolのエントリを1つ取得します。これは問題ありません。次に、そのエントリのol.itの結果を取得します。 size()== 1のリストですが、今回はsize()== 2のエントリがあります。私たちは、そこに外側のループを適用し、同じ結果を得ることができ、我々がしたい場合は、:複数のノードを表す任意のGPathResultで

    html."**".grep { [email protected] == 'divclass' }.ol.li.each { it.each { linkItem -> 
        def link = [email protected] 
        def address = linkItem.address 
        println "$link: $address\n" 
    }} 
    

    、我々はすべてのテキストの連結を取得します。これが最初の結果です。最初は@hrefの場合、の場合はです。

    0

    以前の回答は、使用時のバージョンでは書面ですべて正しいと思います。しかし、私はGroovy 2.3.7でHTTPBuilder 0.7.1とGrails 2.4.4を使用しています。大きな問題があります。HTML要素は大文字に変換されます。これは、デバッグに非常にイライラさせられた

    html.'**'.find { [email protected] == 'divclass' }.OL.LI.each { linkItem -> 
        def link = [email protected] 
        def address = linkItem.ADDRESS.text() 
        println "$link: $address\n" 
    } 
    

    :このための

    http://nekohtml.sourceforge.net/faq.html#uppercase

    を、受け入れ答えで解決策のように書かれている必要があります原因NekoHTMLにボンネットの下で使用されて表示されますそれが誰かを助けることを願っ

    関連する問題