是否可以使用Groovy XMLSlurper解析子树

是否可以使用Groovy XMLSlurper解析子树,groovy,xmlslurper,Groovy,Xmlslurper,有人知道是否有可能以一种方式使用XMLSlurper,即可以从一个非常大的XML文档中提取单个子树并单独处理 假设您有一个巨大的XML提要,其中包含一个根元素,该根元素有数千个可以单独处理的直接子元素。显然,将整个文档读入内存是不可能的,但是,由于根元素的每个子元素本身的大小都比较小,所以最好在文档中进行流式处理,但依次将XMLSlurper niceness应用于每个子元素。在处理每个子元素时,垃圾收集可以清理用于处理它的内存。通过这种方式,我们可以非常轻松地使用XMLSlurper(如此简洁

有人知道是否有可能以一种方式使用XMLSlurper,即可以从一个非常大的XML文档中提取单个子树并单独处理

假设您有一个巨大的XML提要,其中包含一个根元素,该根元素有数千个可以单独处理的直接子元素。显然,将整个文档读入内存是不可能的,但是,由于根元素的每个子元素本身的大小都比较小,所以最好在文档中进行流式处理,但依次将XMLSlurper niceness应用于每个子元素。在处理每个子元素时,垃圾收集可以清理用于处理它的内存。通过这种方式,我们可以非常轻松地使用XMLSlurper(如此简洁的语法),并且流式处理(例如SAX)的内存占用很低


我想知道是否有人对此有想法和/或您自己是否遇到过此要求。

初始化
XmlSlurper
实例意味着调用其重载的
parse(…)
方法(或
parseText(String)
方法)。在这个调用中,XmlSlurper将(至少使用SAX事件)构造一个内存中的
GPathResult
,它保存关于XML元素和属性及其结构的完整信息

因此,不,
XmlSlurper
只提供解析XML文档部分的API


可以做的是,
extend
ing
XmlSlurper
,覆盖
parse*(..)
方法,通过预处理XML,收集XML的所需部分,并将其转发到
XmlSlurper.parse*(..)方法之一
方法。

您可以将StAX API与
XmlSlurper
一起使用来解析子树

// Example of using StAX to split a large XML document and parse a single element using XmlSlurper

import javax.xml.stream.XMLInputFactory
import javax.xml.stream.XMLStreamReader
import javax.xml.transform.Transformer
import javax.xml.transform.TransformerFactory
import javax.xml.transform.sax.SAXResult
import javax.xml.transform.stax.StAXSource

def url = new URL("http://repo2.maven.org/maven2/archetype-catalog.xml")
url.withInputStream { inputStream ->
    def xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream)
    def transformer = TransformerFactory.newInstance().newTransformer()
    while (xmlStreamReader.hasNext()) {
        xmlStreamReader.next()
        if (xmlStreamReader.isStartElement() && xmlStreamReader.getLocalName() == 'archetype') {
            // Example of splitting a large XML document and parsing a single element with XmlSlurper at a time
            def xmlSlurper = new XmlSlurper()
            transformer.transform(new StAXSource(xmlStreamReader), new SAXResult(xmlSlurper))
            def archetype = xmlSlurper.document
            println "${archetype.groupId} ${archetype.artifactId} ${archetype.version}"
        }
    }
}

谢谢-我的结论是,我必须这样做。然而,这确实意味着我必须做一个双重传递,因此它确实会影响性能。我不久前在Twitter上回答了这个问题,所以我决定将答案也添加到这个问题上。