6

ここで私が見逃している明らかなことを誰かが指摘してくれることを願っています。私はこれを何百回もやったような気がしますが、何らかの理由で今夜、これから起こる行動が私をループに投げ込んでいます.

パブリック API から XML を読み込んでいます。さまざまな子ノードも含む特定のノード (「本文」内のすべて) からすべてのテキストを抽出したいと考えています。簡単な例:

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

したがって、最終的には、目的のノード (ここでも「本文」) 内のツリーをトラバースし、含まれるすべてのテキストを自然な順序で抽出したいと考えています。簡単なので、この小さな Groovy スクリプトを作成します...

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()
    }   
}

...これは、「メソッドのシグネチャがありません: java.lang.String.children()」で爆発します。だから私は「待って、何?私は気が狂ってしまうの?」と考えています。Node.depthFirst() は、ノードのリストのみを返す必要があります。「instanceof」チェックを少し追加すると、確かに、Node オブジェクトと String オブジェクトの組み合わせが得られます。具体的には、同じ行のエンティティ内にない行は、文字列として返されます。別名、"This contains" および "and" です。それ以外はすべてノードです (予想どおり)。

これは簡単に回避できます。ただし、これは正しい動作のようには見えません。誰かが私を正しい方向に向けてくれることを願っています。

4

1 に答える 1

7

私はそれが正しい動作だと確信しています (ただし、XmlSlurper と XmlParser には厄介な API があることが常にわかっています)。反復できるすべてのものは、実際にはノード インターフェイス IMO を実装する必要があり、それらからテキストを取得するために使用できる typeofを持つ可能性があります。TEXT

これらのテキスト ノードは有効なノードであり、多くの場合、XML で深さ優先のトラバーサルを実行するため、ヒットする必要があります。それらが返されなかった場合、一部のノード (<p>タグなど) にテキストと要素が混在しているため、子サイズ 1 が機能しないかどうかを確認するアルゴリズムが機能しません。

また、上記のようdepthFirstに、テキストが唯一の子であるすべてのテキスト ノードを一貫して返さないのはなぜでしょうかitalic

私は groovy メソッドのシグネチャを使用して、次のように ( のようなものを使用するのではなくinstanceof) 各ノードを処理する正しい方法をランタイムに判断させる傾向があります。

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(" ")

版画

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

あるいは、XmlSlurperクラスはおそらくあなたが望む/期待することをより多く行い、text()メソッドからのより合理的な出力セットを持っています。結果を使用してDOMウォーキングを行う必要が本当にない場合(XmlParser「より良い」もの)は、次のことをお勧めしXmlSlurperます。

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

版画:

A Title
                    This contains 
                    italics 
                    and
                    xref's
                    .
                Second Title
于 2012-12-20T05:40:09.727 に答える