如何在Groovy中打印当前XML节点的路径?

How to print the path for current XML node in Groovy?

我正在遍历 XML 文件,并希望为每个节点打印 gpath 值。我花了一天时间阅读 Groovy API 文档并尝试一些东西,但似乎我认为很简单,并没有以任何明显的方式实现。

这是一些代码,显示了您可以从 NodeChild 获得的不同内容。

    import groovy.util.XmlSlurper

    def myXmlString = '''
    <transaction>
        <payment>
            <txID>68246894</txID>
            <customerName>Huey</customerName>
            <accountNo type="Current">15778047</accountNo>
            <txAmount>899</txAmount>
        </payment>
        <receipt>
            <txID>68246895</txID>
            <customerName>Dewey</customerName>
            <accountNo type="Current">16288</accountNo>
            <txAmount>120</txAmount>
        </receipt>
        <payment>
            <txID>68246896</txID>
            <customerName>Louie</customerName>
            <accountNo type="Savings">89257067</accountNo>
            <txAmount>210</txAmount>
        </payment>
        <payment>
            <txID>68246897</txID>
            <customerName>Dewey</customerName>
            <accountNo type="Cheque">123321</accountNo>
            <txAmount>500</txAmount>
        </payment>
    </transaction>
    '''

    def transaction = new XmlSlurper().parseText(myXmlString)

    def nodes = transaction.'*'.depthFirst().findAll { it.name() != '' }

    nodes.each { node -> 
        println node
        println node.getClass()
        println node.text()
        println node.name()
        println node.parent()
        println node.children()
        println node.innerText
        println node.GPath
        println node.getProperties()
        println node.attributes()
        node.iterator().each { println "${it.name()} : ${it}" }
        println node.namespaceURI()
        println node.getProperties().get('body').toString()
        println node.getBody()[0].toString()
        println node.attributes()
    }        

我找到了一个接近我需要的 post groovy Print path and value of elements in xml,但它不能扩展到深度节点(见下面的输出)。

来自 link 的示例代码:

    transaction.'**'.inject([]) { acc, val -> 
        def localText = val.localText() 
        acc << val.name()

        if( localText ) {
            println "${acc.join('.')} : ${localText.join(',')}"
            acc = acc.dropRight(1) // or acc = acc[0..-2]
        }
        acc
    }

示例代码的输出:

    transaction/payment/txID : 68246894
    transaction/payment/customerName : Huey
    transaction/payment/accountNo : 15778047
    transaction/payment/txAmount : 899
    transaction/payment/receipt/txID : 68246895
    transaction/payment/receipt/customerName : Dewey
    transaction/payment/receipt/accountNo : 16288
    transaction/payment/receipt/txAmount : 120
    transaction/payment/receipt/payment/txID : 68246896
    transaction/payment/receipt/payment/customerName : Louie
    transaction/payment/receipt/payment/accountNo : 89257067
    transaction/payment/receipt/payment/txAmount : 210
    transaction/payment/receipt/payment/payment/txID : 68246897
    transaction/payment/receipt/payment/payment/customerName : Dewey
    transaction/payment/receipt/payment/payment/accountNo : 123321
    transaction/payment/receipt/payment/payment/txAmount : 500

除了帮助正确处理之外,我还想了解为什么没有像 node.path 或 node.gpath 这样的简单函数来打印节点的绝对路径。

你可以做这样的事情:

import groovy.util.XmlSlurper
import groovy.util.slurpersupport.GPathResult

def transaction = new XmlSlurper().parseText(myXmlString)

def leaves = transaction.depthFirst().findAll { it.children().size() == 0 }

def path(GPathResult node) {
    def result = [node.name()]
    def pathWalker = [hasNext: { -> node.parent() != node }, next: { -> node = node.parent() }] as Iterator
    (result + pathWalker.collect { it.name() }).reverse().join('/')
}

leaves.each { node -> 
    println "${path(node)} = ${node.text()}"
}        

给出输出:

transaction/payment/txID = 68246894
transaction/payment/customerName = Huey
transaction/payment/accountNo = 15778047
transaction/payment/txAmount = 899
transaction/receipt/txID = 68246895
transaction/receipt/customerName = Dewey
transaction/receipt/accountNo = 16288
transaction/receipt/txAmount = 120
transaction/payment/txID = 68246896
transaction/payment/customerName = Louie
transaction/payment/accountNo = 89257067
transaction/payment/txAmount = 210
transaction/payment/txID = 68246897
transaction/payment/customerName = Dewey
transaction/payment/accountNo = 123321
transaction/payment/txAmount = 500

不确定这是否是您想要的,因为您没有说明原因 "doesn't scale for deep nodes"