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 a
s and b
s from the foo
s, bar
s and baz
es 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]
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.
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.
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