Frage

Ich bin ein HTML-Parser zu schreiben, die tagsoup verwendet eine wohlgeformte Struktur XMLSlurper passieren.

Hier ist der generalisierten Code:

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

Ich würde erwarten, die jeder ich jeden ‚li‘ zu lassen, wählen Sie wiederum, damit ich die entsprechenden href und Adressdaten abrufen kann. Stattdessen habe ich diesen Ausgang bin immer:

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

Ich habe verschiedenes Beispiel im Internet und dieser entweder Deal mit XML geprüft oder sind Einzeiler Beispiele wie „alle Links aus dieser Datei abrufen“. Es ist scheint, dass die it.h3.a. @ href Ausdruck alle hrefs im Text zu sammeln, auch wenn ich es einen Verweis auf den übergeordneten ‚li‘ Knoten bin vorbei.

Können Sie lassen Sie mich wissen:

  • Warum erhalte ich die Ausgabe gezeigt
  • Wie kann ich die href / Adresspaare für jeden ‚li‘ Artikel abrufen

Danke.

War es hilfreich?

Lösung

Ersetzen Sie grep mit 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"
}

dann werden Sie bekommen

#href1: Here is the addressTelephone number: telephone

#href2: Here is another addressAnother telephone: 0845 1111111

grep gibt eine Arraylist kehrt aber eine NodeChild Klasse finden:

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

Ergebnisse in:

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

Wenn Sie also grep Sie könnten dann nisten andere jeweils so nutzen wollte, damit es funktioniert

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

Lange Rede kurzer Sinn, in Ihrem Fall verwendet eher finden als grep.

Andere Tipps

Das war eine schwierige Sache. Wenn es nur ein Element ist mit class = ‚divclass‘ ist die vorherige Antwort sicher in Ordnung. Wenn mehrere Ergebnisse von grep waren, dann ein Fund () für ein einzelnes Ergebnis ist nicht die Antwort. Unter Hinweis darauf, dass das Ergebnis eine Arraylist ist korrekt. eine äußere verschachtelte .each () Schleife einfügen ein GPathResult im Verschluß Parameter div . Von hier unten kann der Bohrer mit dem erwarteten Ergebnis weiter.

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

Das Verhalten des ursprünglichen Codes kann auch ein bisschen mehr von einer Erklärung verwenden. Wenn eine Eigenschaft auf einer Liste in Groovy zugegriffen wird, werden Sie eine neue Liste (gleiche Größe) mit der Eigenschaft, jedes Elements in der Liste bekommen. Die Liste von grep gefunden () hat nur einen Eintrag. Dann erhalten wir einen Eintrag für Immobilien ol , was in Ordnung ist. Als nächstes erhalten wir das Ergebnis von ol.it für diesen Eintrag. Es ist eine Liste der Größe () == 1 wieder, aber diesmal mit einem Eintrag von Größe () == 2. Wir könnten die äußeree Schleife dort anzuwenden und das gleiche Ergebnis erhalten, wenn wir wollen:

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

Auf jedem GPathResult mehrere Knoten darstellt, erhalten wir die Verkettung aller Texte. Das ist das ursprüngliche Ergebnis zuerst für @href , dann Adresse .

Ich glaube, die bisherigen Antworten zum Zeitpunkt des Schreibens sind alle richtig, für die Version verwendet. Aber ich bin mit HTTPBuilder 0.7.1 und Grails 2.4.4 mit Groovy 2.3.7 und es ist ein großes Thema - HTML-Elemente werden in Großbuchstaben umgewandelt Es scheint, dies ist darauf zurückzuführen, NekoHTML unter der Haube verwendet. :

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

Aus diesem Grunde, die Lösung in der akzeptierten Antwort muss wie folgt geschrieben werden:

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

Das war sehr frustrierend zu debuggen, hoffen, dass es jemand hilft.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top