Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change XML tag name

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.

like image 665
Ingo Karkat Avatar asked Feb 18 '13 13:02

Ingo Karkat


People also ask

How do I change a tag in XML?

To Replace Xml TagSelect or position the caret on an xml element. Press Alt+Insert. From the Visual Aid menu, select Replace All Xml Tags. Choose an identifier and press Enter to finish or Esc to abort the operation.

What is tag name in XML?

It allows to create new tags (user defined tags). The first element of XML document is called root element. The simple XML document contain opening tag and closing tag. The XML tags are case sensitive i.e. <root> and <Root> both tags are different. The XML tags are used to define the scope of elements in XML document.

Does XML have custom tags?

Custom tags use XML syntax and are what page authors use. This is an umbrella term that describes the set of classes and conventions that allow programmers to create custom actions and tags within JSP. The tag extension mechanism was added to JSP in version 1.1.

How do I remove a tag in XML?

The end tag functions exactly like a right parenthesis or a closing quotation mark or a right curly brace. It contains no data of its own; it simply ends the most recent (innermost) tag with the same name. XML requires a matching end tag for each start tag.


1 Answers

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

like image 157
tim_yates Avatar answered Sep 27 '22 23:09

tim_yates