The posted solution works if you have unique tags among children of a node.
The problem with collectEntries
is that it only allows unique keys. If you have <to>Jani</to> <to>Bani</to>
the last tag will overwrite the previous one in the resulting Map. To avoid this you can group the children by their name first using groupBy
.
Map xmlToMap(node) {
if( !node.childNodes() ){
[(node.name()): node.text()]
}else{
Map groups = node.children().groupBy { it.name() }
[(node.name()): groups.collectEntries { k, v ->
v.size() == 1 ? xmlToMap(v.first()) : [k, v.collectMany { xmlToMap(it).values() }]
}]
}
}
def xml = '''<note>
<to>Tove</to>
<to>Jani</to>
<to>Bani</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
<foot>
<email>m@m.com</email>
<email>m2@m.com</email>
<sig>hello world</sig>
</foot>
</note>'''
def slurper = new XmlSlurper().parseText(xml)
assert xmlToMap(slurper).note == [to:['Tove', 'Jani', 'Bani'], from:'Jani', heading:'Reminder', body:"Don't forget me this weekend!", foot:[email:['m@m.com', 'm2@m.com'], sig:'hello world']]