groovyjsonpathgpath

JSONPath union "[,]" equivalent in GPath


Consider given JSON

{
  "data": {
    "array": [
      {
        "foo": {"a": "1 foo a", "b": "2 foo b", "c": 512},
        "bar": {"a": "3 bar a", "b": "4 bar b"},
        "baz": {"a": "5 baz a", "b": "6 baz b", "d": 75},
        "other": {"a": 2, "x": 13, "y": 44},
      },
      {
        "foo": {"a": "7 foo a", "b": "8 foo b"},
        "bar": {"a": "9 bar a", "b": "10 bar b"},
        "baz": {"a": "11 baz a", "b": "12 baz b"},
        "other": {"a": 2, "x": 13, "y": 44, "z": 132},
      }
    ]
  }
}

With simple JSONPath I can list all the as and bs from the foos, bars and bazes in respective order

$.data.array[*][foo,bar,baz][a,b]
[
  "1 foo a", "2 foo b",
  "3 bar a", "4 bar b",
  "5 baz a", "6 baz b",
  "7 foo a", "8 foo b",
  "9 bar a", "10 bar b",
  "11 baz a", "12 baz b"
]

Is there any ways to do so using Groovy GPath? The only working(ish) solution I've come up with is:

def json = new JsonSlurper().parseText(jsonText)

json.data.array.foo.a
+ json.data.array.foo.b
+ json.data.array.bar.a
+ json.data.array.bar.b
+ json.data.array.baz.a
+ json.data.array.baz.b

But result is still differs (in order) from JSONPath

[1 foo a, 7 foo a,
 2 foo b, 8 foo b,
 3 bar a, 9 bar a,
 4 bar b, 10 bar b,
 5 baz a, 11 baz a, 
 6 baz b, 12 baz b]

P.S.

I'm using GPath for my Rest-Assured tests, so if there's alternative to get the same result in Rest-Assured, I'd be glad to see it.

P.P.S

Actually I've found another solution

json.data.array
    *.subMap(["foo", "bar", "baz"])*.values().flatten()
    *.subMap(["a", "b"])*.values().flatten()

Which yields the same result as JSONPath

[1 foo a, 2 foo b,
 3 bar a, 4 bar b,
 5 baz a, 6 baz b,
 7 foo a, 8 foo b,
 9 bar a, 10 bar b,
 11 baz a, 12 baz b]

But it's still not the alternative for union operation in JSONPath. For example, there's another, a bit more complex expression:

$.data.array[*][foo,bar,?(@.a == '11 baz a')][a,b]

The GPath alternative for that one would be nothing like subMap solution above.


Solution

  • Thanks to @Xiao I've come up with the closest to JsonPath solution:

    def json = new JsonSlurper().parseText(input) //text is your json string
    
    def result = json.data.array
            .collectMany { [it.foo, it.bar, it.baz] }
            .collectMany { [it.a, it.b] }
    
    println result // [1 foo a, 2 foo b, 3 bar a, 4 bar b, 5 baz a, 6 baz b, 7 foo a, 8 foo b, 9 bar a, 10 bar b, 11 baz a, 12 baz b]
    

    However, if I want alternative for

    $.data.array[*][foo,bar,?(@.a == '11 baz a')][a,b]
    

    the result is way more dirty:

    def result = json.data.array
            .collectMany {
                [it.foo, it.bar] + (it.baz.a == '11 baz a' ? it.baz : [])
            }
            .collectMany { [it.a, it.b] }
    

    I think, if we omit usage with filters, collectMany can be considered as equivalent for [,].

    P.S. Your versions for filtered union are welcomed