xmlgroovystreamingmarkupbuilder

Using String Variables inside StreamingMarkupBuilder().bind{} in Groovy


for the Below code :

def writer = new StringWriter()
writer = new StreamingMarkupBuilder().bind {
Project(){MyTag('Help Me')}
}  
println(writer.toString()) 

the output would be: <Project><MyTag>Help Me</MyTag></Project>

Now if i have "MyTag('Help Me')" in above code as a string var and want to use as shown below

def teststring = "MyTag('Help Me')"
def writer = new StringWriter()
writer = new StreamingMarkupBuilder().bind {
Project(){out<<teststring}
}
println(writer.toString()) 

the output am getting is: MyTag('Help Me')<Project></Project>
but am expecting: <Project><MyTag>Help Me</MyTag></Project>

Am new to groovy,anybody help me with proper implementation or find the mistake for the above case ? Please let me know if I had to use other class other than StreamingMarkupBuilder and XmlMarkupBuilder ? Note that in actual scenario for me the text variable actually contains a lot more of child nodes nested .


Solution

  • You could do something like this; Wrap the node string into a { -> } and evaluate it as a Closure, then set the delegate and call the closure:

    import groovy.xml.*
    
    def nodes = '''MyTag( attr:'help me' ) {
                  |    AnotherTag( 'Help me!' )
                  |}'''.stripMargin()
    
    println XmlUtil.serialize( new StreamingMarkupBuilder().bind {
        Project {
            c = Eval.me( "{ -> $nodes }" )
            c.delegate = delegate
            c()
        }
    } )
    

    Which prints:

    <?xml version="1.0" encoding="UTF-8"?><Project>
      <MyTag attr="help me">
        <AnotherTag>Help me!</AnotherTag>
      </MyTag>
    </Project>
    

    However, you must be careful, as if that nodes String comes from outside your system, it can be used to execute any code that is put in it.

    If you're getting the nodes in a String, why not get them to write XML instead and save you a job? ;-)