简体   繁体   中英

Recursively removing whitespace from JSON field names in Groovy

I have a Groovy process that is receiving troublesome JSON that has attribute/field names containing whitespaces:

{
    "leg bone" : false,
    "connected to  the" : {
        "arm bones " : [
            {
                " fizz" : "buzz",
                "well hello" : "there"
            }
        ]
    }
}

Above, fields such as "leg bone" and "well hello" are causing issues during processing (even though they are technically legal JSON fields). So I want to scan each field (recursively, or in nested fashion) in the incoming JSON and string replace any whitespace with an underscore ("_"). Hence, the above JSON would be converted into:

{
    "leg_bone" : false,
    "connected_to__the" : {
        "arm_bones_" : [
            {
                "_fizz" : "buzz",
                "well_hello" : "there"
            }
        ]
    }
}

Typically I use a JsonSlurper for parsing JSON strings into maps, but I can't seem to figure out how to get the recursion correct. Here's my best attempt so far:

// In reality 'incomingJson' isn't hardcoded as a string literal, but this helps make my actual use case
// an SSCCE.
class JsonMapExperiments {
    static void main(String[] args) {
        String incomingJson = """
        {
            "leg bone" : false,
            "connected to  the" : {
                "arm bones " : [
                    {
                        " fizz" : "buzz",
                        "well hello" : "there"
                    }
                ]
            }
        }
        """
        String fixedJson = fixWhitespaces(new JsonSlurper().parseText(incomingJson))
        println fixedJson
    }

    static String fixWhitespaces(def jsonMap) {
        def fixedMap = [:]
        String regex = ""
        jsonMap.each { key, value ->
            String fixedKey = key.replaceAll('\\s+', '_')
            String fixedValue
            if(value in Map) {
                fixedValue = fixWhitespaces(value)
            } else {
                fixedValue = value
            }

            fixedMap[fixedKey] = fixedValue
        }

        new JsonBuilder(fixedMap).toString()
    }

}

When this runs, the final output is:

{"connected_to_the":"{\"arm_bones_\":\"[{ fizz=buzz, well hello=there}]\"}","leg_bone":"false"}

Which is kinda/sorta close, but not exactly what I need. Any ideas?

Given your input and this script:

def fixWhitespacesInTree(def tree) {
    switch (tree) {
        case Map:
            return tree.collectEntries { k, v ->
                [(k.replaceAll('\\s+', '_')):fixWhitespacesInTree(v)]
            }
        case Collection:
            return tree.collect { e -> fixWhitespacesInTree(e) }
        default :
            return tree
    }
}

def fixWhitespacesInJson(def jsonString) {
    def tree = new JsonSlurper().parseText(jsonString)
    def fixedTree = fixWhitespacesInTree(tree)
    new JsonBuilder(fixedTree).toString()
}


println fixWhitespacesInJson(json)

I got the following results:

{"connected_to_the":{"arm_bones_":[{"_fizz":"buzz","well_hello":"there"}]},"leg_bone":false}

I would, however, suggest that you change the regular expression \\\\s+ to just \\\\s . In the former case. if you have two JSON properties at the same level, one called " fizz" and the other called " fizz" then the translated keys will both be "_fizz" and one will overwrite the other in the final result. In the latter case, the translated keys will be "_fizz" and "__fizz" respectively, and the original content will be preserved.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM