Change XML tag name

孤街浪徒 提交于 2021-02-08 13:56:19

问题


I want to transform an XML document which I have parsed with XmlSlurper. The (identical) XML tag names should be replaced with the value of the id attribute; all other attributes should be dropped. Starting from this code:

def xml = """<tag id="root">
            |  <tag id="foo" other="blah" more="meh">
            |    <tag id="bar" other="huh"/>
            |  </tag>
            |</tag>""".stripMargin()

def root = new XmlSlurper().parseText(xml)

// Some magic here.

println groovy.xml.XmlUtil.serialize(root)

I want to get the following:

<root>
  <foo>
    <bar/>
  </foo>
</root>

(I write test assertions on the XML, and want to simplify the structure for them.) I've read Updating XML with XmlSlurper and searched around, but found no way with replaceNode() or replaceBody() to exchange a node while keeping its children.


回答1:


Adding the 'magic' in to the code in the question gives:

def xml = """<tag id="root">
            |  <tag id="foo" other="blah" more="meh">
            |    <tag id="bar" other="huh"/>
            |  </tag>
            |</tag>""".stripMargin()

def root = new XmlSlurper().parseText(xml)

root.breadthFirst().each { n ->
  n.replaceNode { 
    "${n.@id}"( n.children() )
  }
}

println groovy.xml.XmlUtil.serialize(root)

Which prints:

<?xml version="1.0" encoding="UTF-8"?><root>
  <foo>
    <bar/>
  </foo>
</root>

HOWEVER, this will drop any content in the nodes. To maintain content, we would probably need to use recursion and XmlParser to generate a new doc from the existing one... I'll have a think

More general solution

I think this is more generalised:

import groovy.xml.*

def xml = """<tag id="root">
            |  <tag id="foo" other="blah" more="meh">
            |    <tag id="bar" other="huh">
            |      something
            |    </tag>
            |    <tag id="bar" other="huh">
            |      something else
            |    </tag>
            |    <noid>woo</noid>
            |  </tag>
            |</tag>""".stripMargin()

def root = new XmlParser().parseText( xml )

def munge( builder, node ) {
  if( node instanceof Node && node.children() ) {
    builder."${node.@id ?: node.name()}" {
      node.children().each {
        munge( builder, it )
      }
    }
  }
  else {
    if( node instanceof Node ) {
      "${node.@id ?: node.name()}"()
    }
    else {
      builder.mkp.yield node
    }
  }
}

def w = new StringWriter()
def builder = new MarkupBuilder( w )
munge( builder, root )

println XmlUtil.serialize( w.toString() )

And prints:

<?xml version="1.0" encoding="UTF-8"?><root>
  <foo>
    <bar>something</bar>
    <bar>something else</bar>
    <noid>woo</noid>
  </foo>
</root>

Now passes through nodes with no (or empty) id attributes



来源:https://stackoverflow.com/questions/14937816/change-xml-tag-name

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!