Extracting a subset of attributes with JSONPath2 from two nodes of a json document

Viewed 256

I have the following JSON document:

{
  "A": "A_VALUE",
  "B": {
    "C": [
      {
        "D": {
          "E": "E_VALUE1",
          "F": "F_VALUE1",
          "G": "G_VALUE1"
        },
        "H": ["01", "23" ]
      },
      {
        "D": {
          "E": "E_VALUE2",
          "F": "F_VALUE2",
          "G": "G_VALUE3"
        },
        "H": ["45", "67" ]
      }
    ]
  }
}

and I would like to extract field H using a jsonpath2 expression where I specify a value for E field, for example :

$..C[?(@.D.G="G_VALUE1")].H[1]

The code I use to parse this is the following ( jsonpath version 0.4.3 ):

from jsonpath2.path import Path
s='{ "A": "A_VALUE", "B": { "C": [ { "D": { "E": "E_VALUE1", "F": "F_VALUE1", "G": "G_VALUE1" }, "H": ["01", "23" ] }, { "D": { "E": "E_VALUE2", "F": "F_VALUE2", "G": "G_VALUE3" }, "H": ["45", "67" ] } ] } }"'
p = Path.parse_str("$..C[?(@.D.E=\"E_VALUE1\")].H[1]")
print ([m.current_value for m in p.match(s)])

output

[]

Now, if I use JsonPath evaluator on https://jsonpath.com/ I obtain the following result which is not exatly what I need

$..C[?(@.D.E="E_VALUE1")].H[1]

output

[23,67]

But If I change the expression this way than it works and I obtain what I need;

$..C[?(@.D.E=="E_VALUE1")].H[1]

output

[23]

Same results with other online evaluator such as https://codebeautify.org/jsonpath-tester

So what would be the correct jsonpath expression I should use with jsonpath2 api in order to correctly extract the two required fields ?

2 Answers

You have to use [*] to access individual objects inside an array. This code works -

from jsonpath2.path import Path
import json
s='{ "A": "A_VALUE", "B": { "C": [ { "D": { "E": "E_VALUE1", "F": "F_VALUE1", "G": "G_VALUE1" }, "H": ["01", "23" ] }, { "D": { "E": "E_VALUE2", "F": "F_VALUE2", "G": "G_VALUE3" }, "H": ["45", "67" ] } ] } }'
jso = json.loads(s)
p = Path.parse_str('$..C[*][?(@.D.E="E_VALUE1")].H[1]') # C[*] access each bject in the array
print (*[m.current_value for m in p.match(jso)]) # 23

You can refer to this example from the jsonpath2 docs

You should use the == syntax.

Full disclosure: I've never heard of jsonpath before coming across your question, but being somewhat familiar with XPath, I figured I would read about this tool. I came across a site that can evaluate your expresssion using diffeernt implementations: http://jsonpath.herokuapp.com. The net result was that your expression with = could not be parsed by 3 of the 4 implementations. Moreover, the Goessner implementation returned results that you weren't expecting (all C elements matched and the result was [23,67]. With the == boolean expression, 3 of the 4 implementations provided the expected result of [23]. The Nebhale implementation again complained about the expresssion.

Related