Skip to content

Frimkron/JSONPyth

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JSONPyth

Build Status

Another JSONPath implementation for Python.

Supports:

  • Root $ and current @ node
  • Child operator . or [ ... ]
  • Property access (including single quote ' and double " quote delimited names)
  • Recursive descent ..
  • Wildcard *
  • Sets of names/indices [a,b,c]
  • Array slice [start:end:step] (including negative values)
  • Python script expression ( ... ) and filter expression ?( ... ) using $ and @

Requirements

Requires Python 3.5+ and depends on the PyParsing package.

Installation

JSONPyth can be git-cloned directly from Github and installed along with its dependencies using pip:

$ pip install git+https://github.com/Frimkron/JSONPyth#egg=JSONPyth

Or the source can be downloaded manually and then installed by running the setup.py script:

$ python setup.py install

Usage

First parse some JSON data into a Python structure, for example using the json package from the standard library:

import json

# parse some JSON from a string
data = json.loads("""
    {
        "cakes": [
            { "name": "red velvet", "rating": 4.5 },
            { "name": "battenberg" },
            { "name": "jaffa cakes", "rating": 5.0 }
        ],
        "biscuits": [
            { "name": "bourbon", "rating": 5.0 },
            { "name": "custard cream", "rating": 3.5 },
            { "name": "pink wafer", "rating": null },
            { "name": "nice" }
        ]
    }
""")

Then the data can be queried with a JSONPath expression:

from jsonpyth import jsonpath

result = jsonpath(data, '$.biscuits[*].rating')

for r in result:
    print(r)
    

The example above would print the following output:

5
3.5
None

Returning Paths

By default the value of each result is returned. To obtain the normalised path of each result instead, set the result_type parameter to RESULT_TYPE_PATH, or RESULT_TYPE_BOTH can be used to return 2-tuples containing both the value and the path:

from jsonpyth import jsonpath, RESULT_TYPE_BOTH

result = jsonpath(data, '$.biscuits[*].rating', result_type=RESULT_TYPE_BOTH):

for r in result:
    print(r)

Output:

(5, '$["biscuits"][0]["rating"]')
(3.5, '$["biscuits"][1]["rating"]')
(None, '$["biscuits"][2]["rating"]')

Python Expressions

A JSONPath script expression (enclosed in parentheses (...) ) can be used to evaluate a Python statement to provide a dictionary key as a string, or list index as a number. Return values of other types will be ignored.

As parentheses are used to delimit the expression, parentheses used in the script itself must be escaped with a backslash \.

The special symbols @ (current node) and $ (root node) will be substituted for variables named __current and __root respectively, using a simple text replacement before the statement is evaluated. To use a literal @ or $ in the script, it must be escaped with two backslashes \\. Note that a string literal will recognise \\ as an escaped backslash; in such a case each backslash must be further escaped ("\\\\@") or else a raw literal used (r"\\@").

An example script expression:

result = jsonpath(data, r'$.cakes[(len\(@\)-1)].name')

for r in result:
    print(r)

Output:

jaffa cakes

NOTE JSONPyth calls eval to evaluate Python script, and so is unsafe to use for JSONPath expressions from untrusted sources.

Python Filters

Similar to expressions, filters ( ?(...) ) use a Python statement to test whether to include a node or not. The truthiness of the resulting value will be tested using bool, and if False the node will be omitted.

Example:

result = jsonpath(data, r'$[*][?(@["name"].startswith\("b"\))]')

for r in result:
    print(r)

Output:

{"name": "battenberg"}
{"name": "bourbon", "rating": 5}

Credits and Licence

JSONPyth was written by Mark Frimston and is licenced using the the MIT licence. The full text of this licence can be found in the LICENCE.txt file.