jsonxmlgroovyxml-to-json

Groovy convert XML to JSON Array


This is my XML

<ErrorMessage>
   <Code>BUSINESS_EXCEPTION</Code>
   <Message>Invalid postcode - Invalid state</Message>
   <ExtendedStatus>
      <Code>48</Code>
      <Message>Invalid Postcode</Message>
   </ExtendedStatus>
   <ExtendedStatus>
      <Code>12</Code>
      <Message>Invalid State</Message>
   </ExtendedStatus>
</ErrorMessage>

Trying to convert it to following JSON

{
   "code": "BUSINESS_EXCEPTION",
   "message": "Invalid postcode - Invalid state",
   "extendedMessages": [
      {
         "code": "48",
         "message": "Invalid Postcode"
      },
      {
         "code": "12",
         "message": "Invalid State"
      }
   ]
}

I am trying to use following code but it's not generating the expected result:

def toJsonBuilder(xml){
    def pojo = build(new XmlParser().parseText(xml))
    new groovy.json.JsonBuilder(pojo)
}
def build(node){
    if (node instanceof String){ 
        return // ignore strings...
    }
    def map = ['name': node.name()]
    if (!node.attributes().isEmpty()) {
        map.put('attributes', node.attributes().collectEntries{it})     
    }
    if (!node.children().isEmpty() && !(node.children().get(0) instanceof String)) {
        map.put('extendedMessages', node.children().collect{build(it)}.findAll{it != null})
    } else if (node.text() != ''){

        map.put('message', node.text())
    }
    map
}
toJsonBuilder(xml1).toPrettyString()

Solution

  • For such a simple format, I'd only pick the attributes you are interested and transform it. Your example seems not to show any irregularities, that would make me do more defensive stuff like checking for text nodes etc.

    E.g. have one function to build a "code + message" map. Then iterate the ExtendedStatus nodes and collect with the same function:

    def codeAndMessage(node) {
        [code: node.Code.text(),
         message: node.Message.text()]
    }
    
    def build(node){
        codeAndMessage(node) +
        [extendedMessages: node.ExtendedStatus.collect{ codeAndMessage it }]
    }