2012-12-20 19 views
5

Birinin sadece burada eksik olduğum belli bir şeyi işaret edeceğini umuyorum. Bunu yüzlerce kez yaptım ve bu gece bir sebepten dolayı, bundan kaynaklanan davranış beni bir döngü için atıyor.Groovy Node.depthFirst() bir düğüm ve dizge listesi döndürüyor?

Bazı XML'de bir genel API'den okurum. Tüm metni, çeşitli çocuk düğümlerini de içeren belirli bir düğümden ('beden' içindeki her şeyden) çıkarmak istiyorum. Basit bir örnek:

<xml> 
    <metadata> 
     <article> 
      <body> 
       <sec> 
        <title>A Title</title> 
        <p> 
         This contains 
         <italic>italics</italic> 
         and 
         <xref ref-type="bibr">xref's</xref> 
         . 
        </p> 
       </sec> 
       <sec> 
        <title>Second Title</title> 
       </sec> 
      </body> 
     </article> 
    </metadata> 
</xml> 

Yani sonuçta ben arzu düğüm (yine 'body') içindeki ağaç travers ve doğal sırayla bulunan tüm metin ayıklamak istiyorum. Yeterince basit, bu yüzden sadece ... ile havaya uçurmak ilerler

def xmlParser = new XmlParser() 
def xml = xmlParser.parseText(rawXml) 
xml.metadata.article.body[0].depthFirst().each { node -> 
    if(node.children().size() == 1) { 
     println node.text() 
    } 
} 

... bu küçük Groovy senaryoyu yazma "yönteminin hiçbir imza: java.lang.String.children()". Yani kendime "bekle, ne? Ben deliriyor muyum?" Diye düşünüyorum. Node.depthFirst() yalnızca bir düğüm listesi döndürmelidir. Biraz 'instanceof' kontrolünü ekledim ve eminim ki, Node nesneleri ve String nesneleri bir araya getiriyorum. Özellikle, aynı satırdaki varlıklar içinde olmayan satırlar, String'in, "Bu içerir" ve "ve" gibi döndürülür. Her şey bir Düğüm (beklendiği gibi).

Bu konuda kolayca çalışabilirim. Ancak, bu doğru davranış gibi görünmüyor ve birisinin beni doğru yönde göstermesini umuyorum.

+0

Bildiğim kadarıyla Anlattığım gibi, Node.depthFirst, 1.7'de beklediğiniz gibi davrandı. Groovy 2.0 + 'da, Nodes/Strings ile aynı sonuçları görüyorum. – Joseph

cevap

7

Bu doğru davranış olduğundan eminim (her zaman XmlSlurper ve XmlParser'ı çakıştırıcı API'lere sahip oldum). Gerçekten yineleyebileceğiniz her şey bir düğüm arabirimi IMO'yu uygulamalıdır ve potansiyel olarak type'un TEXT numarasına sahip olmalıdır.

Bu metin düğümleri, birçok durumda XML yoluyla ilk geçiş derinliğinde yaptığı gibi vurmak istediğiniz geçerli düğümlerdir. Eğer geri dönmediyse, 1'inin büyüklüğünde olup olmadığını kontrol etmek için algoritmanız, bazı düğümlerin (<p> etiketi gibi) hem karışık metinleri hem de altındaki öğeleri içerdiğinden dolayı işe yaramaz.

Ayrıca, neden italic gibi metnin tek çocuk olduğu, depthFirst sürekli olarak tüm metin düğümlerini döndürmez, bu, işleri daha da kötüye yapar.

def rawXml = """<xml> 
    <metadata> 
     <article> 
      <body> 
       <sec> 
        <title>A Title</title> 
        <p> 
         This contains 
         <italic>italics</italic> 
         and 
         <xref ref-type="bibr">xref's</xref> 
         . 
        </p> 
       </sec> 
       <sec> 
        <title>Second Title</title> 
       </sec> 
      </body> 
     </article> 
    </metadata> 
</xml>""" 

def processNode(String nodeText) { 
    return nodeText 
} 

def processNode(Object node) { 
    if(node.children().size() == 1) { 
     return node.text() 
    } 
} 

def xmlParser = new XmlParser() 
def xml = xmlParser.parseText(rawXml) 
def xmlText = xml.metadata.article.body[0].'**'.findResults { node -> 
    processNode(node) 
} 

println xmlText.join(" ") 

Baskılar

:

böyle (daha doğrusu instanceof gibi bir şey kullanmaktan daha) her düğümü işlemek için doğru yolu olan çalışma zamanı figürü salmak için harika yöntemlerden imzasını kullanmak ister eğilimindedir

A Title This contains italics and xref's . Second Title 

Alternatif XmlSlurper sınıf muhtemelen/istediğiniz o beklediğiniz fazlasını yapar ve text() yönteminden çıktısı daha makul kümesi vardır. Eğer gerçekten (için "daha iyi" olanı XmlParser) sonuçları ile yürüyen DOM herhangi bir sıralama yapmak gerekmez, ben XmlSlurper öneririm:

def xmlParser = new XmlSlurper() 
def xml = xmlParser.parseText(rawXml) 
def bodyText = xml.metadata.article.body[0].text() 
println bodyText 

Baskılar:

A Title 
        This contains 
        italics 
        and 
        xref's 
        . 
       Second Title 
+0

Son bit benim tek istediğim ve tam olarak beklediğim şey.Yemin edebilirdim, bunu denedim, ama her seferinde bir döngü için attığım her seferinde deepFirst() 'i bıraktım. – James

+0

Oh, bu ve bu GPathResult.text() Node.text() çok farklı davranır gerçeği. Dokümanlar biraz daha bilgilendirici olsaydı ... – James

+0

Lütfen Double "*" –