5

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?

JoeG
  • 7,191
  • 10
  • 60
  • 105
  • You need to get a map for the given type and body that encloses this map? – Opal Jan 22 '15 at 18:45
  • Also please provide a valid json file. – Opal Jan 22 '15 at 18:47
  • 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. – JoeG Jan 22 '15 at 18:52
  • I will try to pare down an actual json file - all the ones I have are far too large – JoeG Jan 22 '15 at 18:53
  • Where did you find such a weird json file? – Opal Jan 22 '15 at 21:20

1 Answers1

11

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
cfrick
  • 35,203
  • 6
  • 56
  • 68
  • 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! – JoeG Jan 23 '15 at 14:57