【问题标题】:How to print the path for current XML node in Groovy?如何在 Groovy 中打印当前 XML 节点的路径?
【发布时间】:2019-04-12 09:08:59
【问题描述】:

我正在遍历一个 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()
    }        

我发现一个帖子 groovy Print path and value of elements in xml 接近我的需要,但它不适用于深节点(请参阅下面的输出)。

链接中的示例代码:

    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 这样的简单函数来打印节点的绝对路径。

【问题讨论】:

    标签: groovy xmlslurper


    【解决方案1】:

    你可以这样做:

    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
    

    不确定这是否是您想要的,因为您没有说明为什么它“不能针对深层节点进行扩展”

    【讨论】:

    • 谢谢蒂姆,这似乎有效,我会研究它以了解您是如何做到的 :-) 我的意思是其他解决方案不缩放是一些元素在输出中重复并且它们交叉-叉。看这个:transaction/payment/receipt/payment/payment/txID
    • 它的工作原理是从叶节点返回到根节点(其中 parent == 节点)并收集节点名称,然后反转列表并将它们粘在一起形成一个由 / 分隔的字符串:-)
    猜你喜欢
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多