Pull out nested Maps/EntrySets from JSON with Groovy when criteria met
Asked Answered
L

1

6

Big trouble out in code-land and thus I am in need of help!

Using Groovy and JsonSlurper I am processing JSON of the form below. I am looking for the outside containing element (in my case this all SHOULD be Maps) when a "type" key is set to a certain value. For instance, if the type was "Type5", then I need to get three Maps back: the 'body' Map that contains the outer Type5, the 'body' Map that contains the INNER Type5, and the Type5 Map near the bottom (an EntrySet for each would work fine as well). Type3 and Type4 exhibit the same behavior!

Edited per request to have valid Json

I ran this through Groovy's JsonSlurper so it should be valid.

{
"type": "Run1",
"body": [
{
  "type": "Type1",
  "expression": {
    "type": "Type2",
    "expressions": [
      {
        "type": "Type3",
        "body": {
          "type": "Type4",
          "id": null,
          "params": [
            {
              "type": "Identifier",
              "name": "a"
            },
            {
              "type": "Identifier",
              "name": "b"
            },
            {
              "type": "Identifier",
              "name": "c"
            }
          ],
          "body": {
            "type": "Type5",
            "body": [
              {
                "type": "Type6",
                "id": {
                  "type": "Identifier",
                  "name": "d"
                },
                "params": [
                  {
                    "type": "Identifier",
                    "name": "a"
                  }
                ],
                "body": {
                  "type": "Type5",
                  "body": [
                    {
                      "type": "Type7",
                      "contents": {
                        "type": "Type8",
                        "leftcontents": {
                          "type": "Literal",
                          "value": "specific name",
                        },
                        "rightcontents": {
                          "type": "Type3",
                          "body": {
                            "type": "Type4",
                            "object": {
                              "type": "Identifier",
                              "name": "o"
                            },
                            "property": {
                              "type": "Identifier",
                              "name": "f"
                            }
                          },
                          "contents": [
                            {
                              "type": "Identifier",
                              "name": "a"
                            }
                          ]
                        }
                      }
                    }
                  ]
                },
              },
              {
                "type": "Type6",
                "id": {
                  "type": "Identifier",
                  "name": "e"
                },
                "params": [
                  {
                    "type": "Identifier",
                    "name": "a"
                  }
                ],
                "defaults": [],
                "body": {
                  "type": "Type5",
                  "body": [
                    {
                      "type": "Type7",
                      "contents": {
                        "type": "Type8",
                        "leftcontents": {
                          "type": "Literal",
                          "value": "string",
                        },
                        "rightcontents": {
                          "type": "Type9",
                          "argument": {
                            "type": "Identifier",
                            "name": "a"
                          },
                          "prefix": true
                        }
                      }
                    }
                  ]
                },
              }
            ]
          }
        }
      }
    ]
  }
}
]
}

I am just doing this:

FileInputStream fis = new FileInputStream('myInput.json')
def jsonData = (new JsonSlurper()).parse(fis)

although I can readily access individual parts of the structure, to get all the "Type5"s that have arbitrary nesting levels is beyond me. Can anyone shine some brilliance on this?

Longstanding answered 22/1, 2015 at 18:42 Comment(5)
You need to get a map for the given type and body that encloses this map?Tiphane
Also please provide a valid json file.Tiphane
Yes, for the example above using OmegaType, I would need an EntrySet with a Key of 'a1' and value the corresponding Map. Or just the Map. But I need to get a list (or an iterative way of processing the whole Json) to get subsequent instances of OmegaType (there will be many). So the next one in the example above has a Key of "body" with another Value that is a Map.Longstanding
I will try to pare down an actual json file - all the ones I have are far too largeLongstanding
Where did you find such a weird json file?Tiphane
R
12

Basically you would collect all maps and recurse on collections and on all map values. E.g.:

def json='{"type":"Run1","body":[{"type":"Type1","expression":{"type":"Type2","expressions":[{"type":"Type3","body":{"type":"Type4","id":null,"params":[{"type":"Identifier","name":"a"},{"type":"Identifier","name":"b"},{"type":"Identifier","name":"c"}],"body":{"type":"Type5","body":[{"type":"Type6","id":{"type":"Identifier","name":"d"},"params":[{"type":"Identifier","name":"a"}],"body":{"type":"Type5","body":[{"type":"Type7","contents":{"type":"Type8","leftcontents":{"type":"Literal","value":"specificname",},"rightcontents":{"type":"Type3","body":{"type":"Type4","object":{"type":"Identifier","name":"o"},"property":{"type":"Identifier","name":"f"}},"contents":[{"type":"Identifier","name":"a"}]}}}]},},{"type":"Type6","id":{"type":"Identifier","name":"e"},"params":[{"type":"Identifier","name":"a"}],"defaults":[],"body":{"type":"Type5","body":[{"type":"Type7","contents":{"type":"Type8","leftcontents":{"type":"Literal","value":"string",},"rightcontents":{"type":"Type9","argument":{"type":"Identifier","name":"a"},"prefix":true}}}]},}]}}}]}}]}'
def slrp = new groovy.json.JsonSlurper().parseText(json)

def collectMaps(e) {
    e.with{
        if (it instanceof Map) {
            [it] + it.values().collect{ collectMaps(it) }
        } else if (it instanceof Collection) {
            it.collect{ collectMaps(it) }
        } else {
            []
        }
    }.flatten()
}

assert collectMaps(slrp).findAll{ it.type=='Type5' }.size()==3
assert collectMaps(slrp).findAll{ it.type=='Type3' }.size()==2
Rationale answered 22/1, 2015 at 22:49 Comment(1)
I have looked at this further now and it is SO much better than the solution I was still working - to everyone else, please upvote - it doesn't cost you anything!Longstanding

© 2022 - 2024 — McMap. All rights reserved.