-->

Groovy的Node.depthFirst()返回节点和字符串列表?(Groovy Node.de

2019-08-04 09:14发布

我希望有人将刚指出,我在这里失踪了一些东西明显。 我觉得像我这样做一百次,由于某种原因,今晚,从这个未来的行为是扔我一个循环。

我在一些XML从公共API阅读。 我想提取所有从某个节点(一切“体”内),其中还包括各种子节点的文本。 简单的例子:

<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对象的组合。 特别是不在同一行上的实体线返回字符串的,又名“这包含”与“和”。 一切是一个节点(如预期)。

我可以解决这一点很容易。 然而,这似乎是正确的行为不,我希望有人能指出我在正确的方向。

Answer 1:

我敢肯定这是正确的行为(虽然我总是发现的XmlSlurper和XmlParser的有扭曲的API)。 您可以通过迭代真的所有事情应该IMO实现一个节点接口,并可能有一个typeTEXT ,你可以用它来知道从他们那里得到的文本。

这些文本节点是,在许多情况下,你想打,因为它没有通过XML的深度优先遍历有效节点。 如果他们没有得到恢复,您的检查,如果1儿童尺寸是行不通的,因为一些节点(如算法<p>标签),同时具有混合文本和它下面的元素。

另外,为什么depthFirst并不一致地返回所有文本节点,其中文本是独生子女,如italic以上,使事情变得更糟。

我倾向于喜欢使用的常规方法的签名,让运行弄明白这是处理每一个节点(而不是使用像正道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


文章来源: Groovy Node.depthFirst() returning a List of Nodes and Strings?