Groovy mapping question

I hope it’s ok to ask a general groovy question here, which is something I’m trying to do in a Katalon script, but it’s not really anything to do with Katalon itself!

Is there a way to pass a map as a method parameter, and convert each item in the map to a variable?

For example, consider the following…

def map = [name: "Jerry", age: 42, city: "New York"]
myFunction( map )

def myFunction( myMapParameter ) {
                def name = myMapParameter.get( "name" )
                def age = myMapParameter.get( "age" )
                def city = myMapParameter.get( "city" )

                def xml = """
                <Data>
                                <Name>${name}</Name>
                                <Age>${age}</Age>
                                <City>${city}</City>
                </Data>
                """

                println xml
}

Sure this works, but the code is ugly. I could change the syntax in the XML to directly call the get methods directly (for example ${ myMapParameter.get( “name” )}), but I don’t like this much either. I really want to keep the XML syntax as it is, if possible, which I think it is (I just don’t know how!).

It must be possible, because the findTestObject method can do it, when you pass a map as the second parameter!

I do not see what you want to achieve. Please elaborate what you want a bit more?

No problem, thanks for helping. What I am trying to do in my function is similar to what you can do with the findTestObject function. For example, consider that I have a simple SOAP web service test, and the request object is saved in the repository as “SOAP Service/MyWebServiceRequest”, with the following request message…

<Data>
   <Name>${name}</Name>
   <Age>${age}</Age>
   <City>${city}</City>
</Data>

One way I could pass the three variables is to create a map and pass the map using the findTestObject function, as follows…

def map = [name: “Jerry”, age: 42, city: “New York”]
WS.sendRequest( findTestObject( ‘SOAP Service/MyWebServiceRequest’, map ) )

I’ve used this mechanism in my web service tests in the past, with a function I created that builds the map by reading from a row of data in a spreadsheet, it does exactly what I want and is very efficient. However, now I need to do something similar in a function of my own. I want to call my function with a map, and have it return XML with the variables substituted within it. Ideally I’d like to use the same ‘syntax’ in my function (${name}), so that it’s familiar to anyone that might want to maintain it in future.
I hope this makes sense, it’s hard to describe simply.

You already know that, but you are know aware that you know that. Read the doc:

Ooh thanks, this gets me much closer to what I want, but can I be greedy and ask if we can take it the final step please?

Using the link you sent, I’ve now got the example code like this…

def map = [name: "Jerry", age: 42, city: "New York"]
myFunction( map )

def myFunction( myMap ) {
    def xml = """
        <Data>
            <Name>${myMap.name}</Name>
            <Age>${myMap.age}</Age>
            <City>${myMap.city}</City>
        </Data>
        """

	println xml
}

But what I would really like is to avoid specifying “myMap.” in the placeholders. Is there something I can so that the script would know to use the myMap object, so that I can do…

        <Name>${name}</Name>
        <Age>${age}</Age>
        <City>${city}</City>

???

Try the following example:

// See the Groovy lang doc 1.2.2 "Sharing data between a script and the application"
// at http://docs.groovy-lang.org/latest/html/documentation/guide-integrating.html

// You need to enclose the template String with triple single quotes: ''' ... '''
// You should not use triple double quotes: """ ... """
// because here you do not want Groovy to perform interpolating placeholders like ${name} to values

def xml = '''
<Data>
	<Name>${name}</Name>
	<Age>${age}</Age>
	<City>${city}</City>
</Data>
'''

String result = myFunction(xml, ["name": "Jerry", "age": 42, "city": "New York"])
println result

def myFunction(String template, Map variables ) {
	def groovyscript = '"""' + template + '"""'       // this line constructs a valid "Groovy script" which contains a single string literal enclosed in a pair of double quotations: """ ... """
	def shell = new GroovyShell(new Binding(variables))
	return shell.evaluate(groovyscript)
}

You can also use SimpleTemplateEngine to perform substitutions on a given multi-line string.
See: https://docs.groovy-lang.org/docs/next/html/documentation/template-engines.html#_simpletemplateengine

Or https://docs.groovy-lang.org/docs/next/html/documentation/template-engines.html#_xmltemplateengine

1 Like

Yes, SimpleTemplateEngine is better for daily use.

1 Like

Thanks to you and bionel - either of these solutions will work for me, this is BRILLIANT! I’ve learned a lot today, thanks you you both. This is really going to help me - most appreciated!