groovymarkupbuilder

Groovy MarkupBuilder passing string by reference


Doing transformation of a JSON feed to a format that can be consumed by our Endeca Instance, and settled on writing this transformation in Groovy, due to tools like JsonSlurper and MarkupBuilder. Our JSON feed input looks like this (saved as stage/newObject.json):

[
  {
    "Name": "Object Name",
    "DimID": 0000,
    "ObjectID": "Object-0000",
    "TypeID": 1,
    "Type": "Object Type",
    "Description": "A Description",
    "DirectorID": "007",
    "DirectorName": "Bond, James",
    "ParentObjectID": null,
    "ObjectLevelID": 1,
    "ObjectLevel": "MI-6",
    "ProjectNumbers": [
        "0001",
        "0002"
    ],
    "ManagerIDs": [
      "001"
    ],
    "ManagerNames": [
      "M"
    ],
    "SubObjectIDs": [
        "006",
        "005"
    ],
    "TaskNumbers": [
        "001"
    ],
    "ProjectNames": [
        "Casino Royal",
        "Goldfinger",
        "License to Kill"
    ]
  }
]

And the code I've got to do the transform is this:

def rawJSONFile = new File("stage/newObject.json")
JsonSlurper slurper = new JsonSlurper()
def slurpedJSON = slurper.parseText(rawJSONFile.text)

def xmlOutput = new MarkupBuilder(new FileWriter(new File("stage/ProcessedOutput.xml")))

xmlOutput.RECORDS() {
    for (object in slurpedJSON) {
        RECORD() {
            for (field in object) {
                if (field.value != null) {
                    if (field.value.value.class.equals(java.util.ArrayList)) {
                        if (field.value.value.size > 0) {
                            for (subField in field.value.value) {
                                if (subField != null) {
                                    PROP(NAME: field.key) {
                                        PVAL(subField)
                                    }
                                }
                            }
                        }
                    } else {
                        PROP(NAME: field.key) {
                            PVAL(field.value)
                        }
                    }
                }
            }
        }
    }
}

The issue we're experiencing is about half way down the groovy script, where it's dealing with sub fields (that is the arrays within the JSON), the closure that's creating the "PVAL" node is passing the subField variable by reference and it's not being treated as a string but a character array, so trying to do the output, we get a Memory location, rather than a String. The workaround we've got so far is this, but I wanted to know if there was a more elegant solution:

for (subField in field.value.value) {
    if (subField != null) {
        PROP(NAME: field.key) {
            StringBuilder subFieldValue = new StringBuilder();
            for(int i =0; i<subField.length; i++){
                subFieldValue.append(subField[i])
            }
            PVAL(subFieldValue.toString())
        }
    }
}

Solution

  • Change subField in field.value.value to subField in field.value in

    for (subField in field.value) {
        if (subField != null) {
            PROP(NAME: field.key) {
                PVAL(subField)
            }
        }
    }
    

    Although this logic can be simplified as

    xmlOutput.RECORDS {
        slurpedJSON.each { map ->
            Record {
                map.each { k, v ->
                    if ( v in ArrayList ) {
                        v.each { val ->
                            PROP(NAME: k) { 
                                PVAL(val)
                            }
                        }
                    } else {
                        PROP(NAME: k) { 
                            PVAL(v)
                        }
                    }
                }
            }
        }
    }