【问题标题】:Deleting nodes in XML using Xpath in Groovy在 Groovy 中使用 Xpath 删除 XML 中的节点
【发布时间】:2012-10-12 20:14:15
【问题描述】:

我有这个 Groovy 代码可以使用 xpath 字符串删除节点,但是我在删除 xpath 导致多个节点实例的节点时遇到问题。

示例 XML...

<root>
  <element1>foo</element1>
  <element2>bar</element2>
  <items>
     <item>
       <name>a</name>
       <desc>b</desc>
     <item>
     <item>
        <name>c</name>
        <desc>x</desc>
     </item>
  </items>
</root>

删除节点的代码...

def resource = XmlSlurper().parseText(xml)
def xpathsToDelete = ['/root/element1','/root/items/item/name']
 xpathsToDelete.each {
     def pathTokens = it.path.tokenize '/'
     def currentNode = resource
     if ( currentNode.name() == pathTokens.first() ) { 
       def xpath = pathTokens.tail().join '/'
       currentNode = currentNode."${xpath}"
       currentNode.replaceNode{}
     }
}

上面的代码使用 xpath /root/element1 删除节点 element1,它计算为单个节点,但不适用于计算为多个节点的 /root/items/name

【问题讨论】:

  • 它会给你一个例外吗?
  • 不,它只是不处理循环节点,我以为我为它编码,但我想我的逻辑不正确

标签: xpath groovy gpath


【解决方案1】:

这是一个棘手的问题。它与this question 相关,这对我的回答至关重要。

这是一个解决方案:

import groovy.util.* 
import groovy.xml.* 

def xml = """<root>
  <element1>foo</element1>
  <element2>bar</element2>
  <items>
     <item>
       <name>a</name>
       <desc>b</desc>
     </item>
     <item>
        <name>c</name>
        <desc>x</desc>
     </item>
  </items>
</root>"""

def removeNodes = { doc, path ->
    def nodes = doc
    path.split("\\.").each { nodes = nodes."${it}" }
    nodes.each { it.replaceNode{} }    
}

def resource = new XmlSlurper().parseText(xml)
def xpathsToDelete = ['/root/element1','/root/items/item/name']

xpathsToDelete.each { xpath ->
    def trimXPath = xpath.replaceFirst( "/root/", "").replace("/",".")
    removeNodes(resource, trimXPath)
}

println XmlUtil.serialize(new StreamingMarkupBuilder().bind {
    mkp.yield resource
})

【讨论】:

  • xpath.replace("/root/", "") 有必要吗?我正在使用不同的 xml 文档,根元素名称会改变,但我很容易获得元素名称,所以也许我可以使用变量而不是硬编码 "/root/" 来设置它
  • 好点。该代码仅存在,因为我试图重现您的确切场景。如果将xpathsToDelete数组中的值改为["element1", "items/item/name"],可以简化代码。
【解决方案2】:

这似乎也有效:

import groovy.xml.*

def xml = '''<root>
            |  <element1>foo</element1>
            |  <element2>bar</element2>
            |  <items>
            |     <item>
            |       <name>a</name>
            |       <desc>b</desc>
            |     </item>
            |     <item>
            |        <name>c</name>
            |        <desc>x</desc>
            |     </item>
            |  </items>
            |</root>'''.stripMargin()

def newxml = new XmlSlurper().parseText( xml ).with { x ->
  [ '/root/element1', '/root/items/item/name' ].each { path ->
    def s = path.split( '/' ).drop( 2 ).inject( x ) { element, p ->
      element."$p"
    }?.replaceNode {}
  }
  x
}

println XmlUtil.serialize(new StreamingMarkupBuilder().bind {
    mkp.yield newxml
})

【讨论】:

  • 这看起来又短又甜,现在测试一下,mkp.yield 是做什么的?
  • 这只是将 newxml 结构按原样传递给 StreamingMarkupBuilder,然后将其传递给 XmlUtil.serialize 以使其更适合打印
猜你喜欢
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多