Question

I have created a string variable using some logic in groovy which reflects the braket syntax in markup builder but the problem is that you are obviously not allowed to use this string in markup builder. The nature of my code makes it necessary. I want to know if there is a way of doing something like the following

def param = "node1{ node2{ node3() } }"
def sw = new StringWriter()
def xml = new groovy.xml.MarkupBuilder(sw)

XML = xml.param

I know the above code is not correct but is there a way of doing what i am driving at? To be clear param is a string which is the product of another piece of code. I am looking to get out a piece of XML like the following:

<node1><node2><node3/></node2><node1>

Thanks

Was it helpful?

Solution

If you change your closure string to be (I've called it builder as I'm not keen on lower-cased class names as property names)

def builder = { ->
    node1 {
        node2{
            node3()
        }
    }
}

You can then do this with StreamingMarkupBuilder:

String output = new groovy.xml.StreamingMarkupBuilder().bind { 
    builder.delegate = delegate
    builder()
}.toString()

And output will contain the String:

<node1><node2><node3/></node2></node1>

Edit:

Looks like I misunderstood and the param variable is a String. In that case, you can do this to evaluate the String (wrapped in a closure) and do much the same as above:

def param = "node1 { node2 { node3() } }"

String output = new groovy.xml.StreamingMarkupBuilder().bind { smb ->
    Eval.me( "{ -> $param }" ).with { c ->
        c.delegate = smb
        c()
    }
}.toString()

It should be noted however, that care must be taken when doing anything with Eval. It won't care if the code is malicious, or benign, it will just run it, possibly crashing your app or deleting code or worse.

Maybe instead of building a String, you could build a map or something? Then you could do something like this:

def param = [ node1:[ node2:[ node3:'' ] ] ]

String output = new groovy.xml.StreamingMarkupBuilder().bind {
    param.each { k, v ->
        "$k" { v instanceof Map ? v.each( owner ) : mkp.yield( v ) }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top