I have some JSON like this:
{
“data”: {
“352670”: {
“humdrum”: true
},
“331230”: {
“humdrum”: false
}
}
I want to extract all the keys under “data” where the value of “humdrum” is true, so in this case I would end up with List(352670). This is what I’ve tried:
.check(jsonPath("/data/(*)/?(humdrum=true)").findAll.saveAs(“humdrums”)))
However I’m getting this error Caused by: class org.jaxen.saxpath.XPathSyntaxException: /data/()/?(humdrum=true): 6: Expected one of ‘.’, ‘…’, ‘@’, '’,
It doesn’t appear that your jsonPath function matches the expectations I have when reading this:
https://code.google.com/p/json-path/
Is there a way to achieve what I’m after?
Stig
Humm … we are just did a breaking change in that part.
- 1.4.X and 2.0-M1 use a XPath like syntax over Json based on Jackson+Jaxen
- 1.5.0-SNAPSHOT and 2.0-SNAPSHOT are now using the librairy you point out (ie : https://code.google.com/p/json-path/)
As you have a Jaxen error, I guess that you’re using 2.0-M1 ?
Here is a 2.0-SNAPSHOT build that will allow to use the more “common” json-path : https://docs.google.com/file/d/0B1zTVlhQrNiyUFhBZzBacGVNZnc/edit
Just so that you know: we plan on releasing 1.5.0 and 2.0.0-M2 on monday.
Go there for the exact syntax: http://goessner.net/articles/JsonPath/
Thanks. I can see how to extract the leaves - is it possible to extract the value of the wildcard (*) in this expression?
$.data.*.?(@==true)
Or do I have to resort to parse JSON with regex? It’ll be dirty, but with this simple JSON I’m sure it can be done…
Stig
Provide a JSON sample and what you’re trying to extract and we can show you the proper syntax.
The JSON I have looks like this (it is simplified, of course):
{
“data”: {
“key-a”: {
“foo”: true
},
“key-b”: {
“foo”: false
},
“key-c”: {
“foo”: true
}
}
I want to extract all the “key-*” where the value of “foo” is true. So from that I expect to end up with:
List(“key-a”, “key-c”)
I tried a lot of things using the JSONPath expression tester, but I wasn’t able to bend it to my will. I then tried to use a transform, before giving up and using a regex. It’s dirty, but it works:
.check(regex(""""(\w+)"\s*:\s*{\s*“foo”\s*:\s*true""")
.findAll.transform(x => x.map(_.toSet)).whatever.saveAs(“foos”)))
Stig
Sadly, what you’re trying to do will never work because you’re trying to gather data from multiple paths. JsonPath, just like XPath, can’t do that.
You would need data to be an array of keys that have a name and a foo.
Regex is a solution.
Another one would be to use a bodyString check, and add a transform step where you would parse it into a JSON AST and extract the values you want.
The JSON engine that’s shipped (actually, will be starting next release) with Gatling is json-smart.
Cheers,
Stéphane
Thank you very much again. I like the bodyString approach better than my regex. It works like a charm (I use spray.json since I’m already familiar with it):
.check(bodyString.transform(x => x.map(y => {
val json = y.asJson.convertTo[Map[String, Map[String, Map[String, Boolean]]]]
json(“data”).filter(_._2(“foo”)).keySet
})).whatever.saveAs(“foos”)))
Stig
Nice.
FYI, with json-smart, you would get something like this:
.check(bodyString.transform(_.map(string => {
val json = parser.parse(is).asInstanceOf[JSONObject]
json.get(“data”).asInstanceOf[JSONObject].collect {
case (key, keyValue: JSONObject) if keyValue.get(“foo”) == true => key
}
})).saveAs(“foos”)))