Groovy markupBuilder updating parent node

2019-08-04 12:24发布

问题:

I'm building xml using MarkupBuilder and wonder how can I update a parent attribute when creating a child node. Assuming the number of child elements cannot be calculated when building the parent element.

 def writer = new StringWriter()
 def xml = new MarkupBuilder(writer)

 xml.parent(totalDuration: 'should be: some of all child duration') {
     child(duration: '1')
     child(duration: '2') 
...  
 }

Is there an elegant way of accessing the parent node from a child node?

Thanks Tal

回答1:

Is there an elegant way of accessing the parent node from a child node?

Not with a MarkupBuilder, which generates the XML in a streaming fashion (it has already written the parent element's opening tag to the output stream before calling the nested closure). But you could use a DOMBuilder to build up a DOM tree in memory, then fill in the total using the DOM API, and finally serialize the DOM tree including the total attribute:

import groovy.xml.*
import groovy.xml.dom.*
import org.w3c.dom.*

def dom = DOMBuilder.newInstance(false, true)
Element parent = dom.parent() {
  child(duration:'1')
  child(duration:'2')
}
use(DOMCategory) {
  parent.setAttributeNS(null, "totalDuration",
                        parent.xpath('sum(child/@duration)'))
}

def xmlString = XmlUtil.serialize(parent)

The DOMBuilder should work the same as a MarkupBuilder as long as you're not using mkp.yield or mkp.yieldUnescaped inside the closure. If you need to use these then you'd have to build up the XML string without the totalDuration attribute, then re-parse it into a DOM, add the extra attribute and re-serialize.