8

TagSoupを使用して整形式の構造体をXMLSlurperに渡すHTMLパーサーを作成しています。

一般化されたコードは次のとおりです。

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 { it.@class == 'divclass' }.ol.li.each { linkItem ->
    def link = linkItem.h3.a.@href
    def address = linkItem.address.text()
    println "$link: $address\n"
}

それぞれが、対応するhrefとアドレスの詳細を取得できるように、それぞれの「li」を順番に選択できるようになることを期待しています。代わりに、次の出力を取得しています。

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

Webでさまざまな例を確認しましたが、これらはXMLを扱っているか、「このファイルからすべてのリンクを取得する」などのワンライナーの例です。it.h3.a.@href式は、親の「li」ノードへの参照を渡していますが、テキスト内のすべてのhrefを収集しているようです。

教えていただけますか:

  • 出力が表示される理由
  • 各「li」アイテムのhref/addressペアを取得する方法

ありがとう。

4

3 に答える 3

11

grepをfindに置き換えます。

html.'**'.find { it.@class == 'divclass' }.ol.li.each { linkItem ->
    def link = linkItem.h3.a.@href
    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を返しますが、findはNodeChildクラスを返します。

println html.'**'.grep { it.@class == 'divclass' }.getClass()
println html.'**'.find { it.@class == 'divclass' }.getClass()

結果:

class java.util.ArrayList
class groovy.util.slurpersupport.NodeChild

したがって、grepを使用したい場合は、このようにそれぞれをネストして機能させることができます。

html.'**'.grep { it.@class == 'divclass' }.ol.li.each {
    it.each { linkItem ->
        def link = linkItem.h3.a.@href
        def address = linkItem.address.text()
        println "$link: $address\n"
    }
}

簡単に言うと、あなたの場合、grepではなくfindを使用してください。

于 2009-11-05T05:48:18.413 に答える
1

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

html."**".grep { it.@class == 'divclass' }.each { div -> div.ol.li.each { linkItem ->
   def link = linkItem.h3.a.@href
   def address = linkItem.address.text()
   println "$link: $address\n"
}}

元のコードの動作には、もう少し説明を使用することもできます。Groovyのリストでプロパティにアクセスすると、リスト内の各要素のプロパティを含む新しいリスト(同じサイズ)が取得されます。grep()によって検出されたリストには、エントリが1つだけあります。次に、プロパティolのエントリを1つ取得します。これは、問題ありません。次に、そのエントリのol.itの結果を取得します。これもsize()== 1のリストですが、今回はsize()== 2のエントリがあります。必要に応じて、そこに外側のループを適用して同じ結果を得ることができます。

html."**".grep { it.@class == 'divclass' }.ol.li.each { it.each { linkItem ->
   def link = linkItem.h3.a.@href
   def address = linkItem.address
   println "$link: $address\n"
}}

複数のノードを表すGPathResultでは、すべてのテキストの連結を取得します。これが元の結果であり、最初は@href、次にアドレスです。

于 2013-04-25T16:12:09.597 に答える
0

使用したバージョンについては、執筆時点で以前の回答はすべて正しいと思います。しかし、私はHTTPBuilder0.7.1とGrails2.4.4をGroovy2.3.​​7で使用しており、大きな問題があります。HTML要素が大文字に変換されます。これは、内部で使用されているNekoHTMLが原因のようです。

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

このため、受け入れられた回答の解決策は次のように記述する必要があります。

html.'**'.find { it.@class == 'divclass' }.OL.LI.each { linkItem ->
    def link = linkItem.H3.A.@href
    def address = linkItem.ADDRESS.text()
    println "$link: $address\n"
}

これはデバッグするのに非常にイライラしました。誰かに役立つことを願っています。

于 2015-03-02T00:36:09.643 に答える