JSONPath 联合“[]”相当于 GPath

JSONPath union "[,]" equivalent in GPath

考虑给定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},
      }
    ]
  }
}

使用简单的 JSONPath 我可以列出 foos、bars 和 [=22] 中的所有 as 和 bs =]es 在各自的顺序

$.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"
]

有什么方法可以使用 Groovy GPath 来实现吗? 我想出的唯一可行的(大概)解决方案是:

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

但结果仍然(按顺序)不同于 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.

我正在使用 GPath 进行我的 Rest-Assured 测试,所以如果有其他方法可以在 Rest-Assured 的情况下获得相同的结果,我会很高兴看到它。

P.P.S

实际上我找到了另一个解决方案

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

与 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]

但它仍然不是 JSONPath 中联合操作的替代方法。 例如,还有一个更复杂的表达式:

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

那个的 GPath 替代方案与 subMap 完全不同 上面的解决方案。

这是解决您问题的纯 gpath 版本,使用 collectMany and collect 方法:

根据 RomanMitasov 的更新问题更新的答案:

def json = new JsonSlurper().parseText(text) //text is your json string
def result = json.data.array*.collectMany{k,v-> k in ["foo","bar","baz"]? v.collect{k1,v1-> k1 in ["a","b"]? v1:[]}:[]}.flatten()
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]

原始答案:

def json = new JsonSlurper().parseText(text) //text is your json string
def result = json.data.array*.collectMany{k,v->v.collect{it.value}}.flatten()
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]

感谢 @Xiao 我想出了最接近 JsonPath 的解决方案:

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]

但是,如果我想要

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

结果更脏:

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

我认为,如果我们省略过滤器的使用,collectMany 可以被认为等同于 [,]

P.S。欢迎使用过滤联合版本