xmlgroovymarkupbuilder

create xml markupBuilder based on external variables


I have seen in plenty of websites the common use of MarkupBuilder xml creator. For example:

def xmlWriter = new StringWriter()
def xmlMarkup = new MarkupBuilder(xmlWriter)
xmlMarkup.movie(id: "2", "the godfather")
println(xmlWriter.toString())

Will give something like this:

<movie id='2'>the godfather</movie>

My question is: ¿Is there a good way to use MarkupBuilder to compose an xml using variables taken from a method?

I have manage to add the root access with this code:

createXml(root){
    def xmlWriter = new StringWriter()
    def xmlMarkupBuilder = new MarkupBuilder(xmlStringWriter)
    xmlMarkupBuilder.createNode(root)
    xmlMarkupBuilder.nodeCompleted(null,root)
}

But I'm pretty sure there must be another clean way to do it. How can I add a new node if I only know the name of the parent node?

I ended up doing this with java DocumentBuilder,

    XmlData(xmlPath, rootNodeName){
       this.xmlPath = xmlPath
       xmlDoc =    DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()
       def rootNode=xmlDoc.createElement(rootNodeName)
       xmlDoc.appendChild(rootNode)
   }

    def addNode(parentNodeName,nodeName,nodeValue,attributes){
       def newNode = xmlDoc.createElement(nodeName)
       if(nodeValue!=null){
          def newTextNode = xmlDoc.createTextNode(nodeValue)
          newNode.appendChild(newTextNode)
       }
       if(attributes!=null){
          attributes.each{key,value ->
            newNode.setAttribute($key,$value)
          }
       }
       def nodeList = xmlDoc.getElementsByTagName(parentNodeName)
       nodeList.item(nodeList.getLength()-1).appendChild(newNode)
   }

but if there is a cleaner way to do this with MarkupBuilder or MarkupBuilderHelper, I would preffer to use that one. The code I would like to get is:

Input:

        def xmlWriter = new XmlWriter("rootNode")
        xmlWriter.addNode("rootNode","",null)
        xmlWriter.addNode("rootNode","child2",null)
        xmlWriter.addNode("child1","child11","text1")
        xmlWriter.addNode("child1","child12","text2")
        xmlWriter.addNode("child2","child21","text3")
        xmlWriter.addNode("child2","child22","text4")

Methods:

class XmlWriter{
    createXml(root){
    def xmlWriter = new StringWriter()
    def xmlMarkupBuilder = new MarkupBuilder(xmlStringWriter)
    xmlMarkupBuilder.createNode(root)
    xmlMarkupBuilder.nodeCompleted(null,root)
    }

    def addNode(parentNodeName,nodeName,nodeValue,attributes){
       ???
    }
}

Output:

<rootNode>
  <child1>
     <child11>test1</child11>
     </child12>test2</child12>
  </child1>
  <child2>
     <child21>test3</child21>
     </child22>test4</child22>
  </child2>
</rootNode>

Note: I don't take into account that could exist several items in nodeList items because in my xml this is not possible at the present moment.


Solution

  • Here's one method to do what I think you want...

    Given some XML:

    def xml = '''<root>
                |    <node>
                |        <anotherNode some="thing">
                |            Woo
                |        </anotherNode>
                |        <stuff>
                |        </stuff>
                |    <node>
                |    </node>
                |        <anotherNode some="thing">
                |            Woo
                |        </anotherNode>
                |        <stuff>
                |        </stuff>
                |    </node>
                |</root>'''.stripMargin()
    

    and given the name of the parent node, the name of the new child node, it's attributes and text content:

    def parentName = 'stuff'
    def nodeName = 'things'
    def nodeContent = 'text'
    def attributes = [ tim: 'yates' ]
    

    We can parse the XML with XmlParser

    import groovy.xml.*
    
    def root = new XmlParser().parseText(xml)
    

    And then find all nodes called parentName and append a new node to each of them:

    root.'**'.findAll { it.name() == parentName }
             .each {
                 it.appendNode(new Node(it, nodeName, attributes, nodeContent))
             }
    

    Then, printing out the xml should show they're there:

    println XmlUtil.serialize(root)