jsonPath: extract key where value is true

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/

And you can also check the spec: https://github.com/excilys/gatling/blob/master/gatling-core/src/test/scala/io/gatling/core/check/extractor/jsonpath/JsonPathExtractorsSpec.scala

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”)))