Package: jsonpath-tp
Thejsonpath_tpPackage.Thejsonpath_tpis ajsonpathimplementation built on top oftreepathtechnology.  Jsonpath isquery languagefor extracting data fromjsondocument.   The jsonpath_tp attempts to follow the
standard defined injsonpathwith
the exceptions:script expression are not supportedfilter (script) expression support any single argument python function.filter expression support regular expressionThe jsonpath_tp can be used programmatically or via th OS command line interface (CLI) with the addition ofjsonpath_cliwith package.Quick Start ProgrammaticallyAll the jsonpath_tp components should be imported as follows:fromjsonpath_tpimportget,findA jsonpath example that gets c's value from json data.data={"a":{"b":[{"c":1},{"c":2}]}}value=get("$.a.b[0].c",data)assertvalue==1A jsonpath example that gets c's value from json data.value=[valueforvalueinfind("$.a.b[*].c",data)]assertvalue==[1,2]Solar System Json DocumentThe examples shown in this README use the following json document.  It describes our solar system. Click to expand.solar_system = {...}{"star":{"name":"Sun","diameter":1391016,"age":null,"planets":{"inner":[{"name":"Mercury","Number of Moons":"0","diameter":4879,"has-moons":false},{"name":"Venus","Number of Moons":"0","diameter":12104,"has-moons":false},{"name":"Earth","Number of Moons":"1","diameter":12756,"has-moons":true},{"name":"Mars","Number of Moons":"2","diameter":6792,"has-moons":true}],"outer":[{"name":"Jupiter","Number of Moons":"79","diameter":142984,"has-moons":true},{"name":"Saturn","Number of Moons":"82","diameter":120536,"has-moons":true},{"name":"Uranus","Number of Moons":"27","diameter":51118,"has-moons":true},{"name":"Neptune","Number of Moons":"14","diameter":49528,"has-moons":true}]}}}query examples.DescriptionXpathjsonpathtreepathFind planet earth./star/planets/inner[name='Earth']$.star.planets.inner[?(@.name=='Earth')]path.star.planets.inner[*][?(@.name == 'Earth')]List the names of all inner planets./star/planets/inner[*].name$.star.planets.inner[*].namepath.star.planets.inner[*].nameList the names of all planets./star/planets/*/name$.star.planets.[].namepath.star.planets.wc[*].nameList the names of all celestial bodies//name$..namepath.rec.nameList all nodes in the tree Preorder//*$..path.recGet the third rock from the sun/star/planets/inner[3]$.star.planets.inner[2]path.star.planets.inner[2]List first two inner planets/star/planets.inner[position()<3]$.star.planets.inner[:2]path.star.planets.inner[0:2]$.star.planets.inner[0, 1]path.star.planets.inner[0, 2]List planets smaller than earth/star/planets/inner[diameter < 1]$.star.planets.inner[?(@.diameter < 12756)]path.star.planets.inner[wc][has(path.diameter < 12756)]List celestial bodies that have planets.//*[planets]/name$..[?(@.planets)].namepath.rec[?(@.planets)].nameList the planets with more than 50 moons$..[?(int(@['Number of Moons']) > 50)].namepath.rec[wc][has(path['Number of Moons'] > 50, int)].nameTraversal FunctionsgetThegetfunction returns the first value the path leads to.Get the star name from the solar_systemsun=get("$.star.name",solar_system)assertsun=='Sun'When there is no match, MatchNotFoundError is thrown.try:get("$.star.human_population",solar_system)assertFalse,"Not expecting humans on the sun"exceptMatchNotFoundError:passOr if preferred, a default value can be given.human_population=get("$.star.human_population",solar_system,default=0)asserthuman_population==0In addition to a constant, the default value may also be a callabledefpopulation():return0human_population=get("$.star.human_population",solar_system,default=population)asserthuman_population==0The default value can be automatically injected in to json documenthuman_population=get("$.star.human_population",solar_system,default=1,store_default=True)asserthuman_population==solar_system['star']["human_population"]findThefindfunction returns an Iterator that iterates to each value the path leads to.  Each value is
determine on its iteration.Find All the planet names.inner_planets=[planetforplanetinfind("$.star.planets.inner[*].name",solar_system)]assertinner_planets==['Mercury','Venus','Earth','Mars']Tracing DebuggingAll the functions: get, find, support tracing.   An option, when enabled,
records the route the algorithm takes to determine a match.This example logs the route the algorithm takes to find the inner planets.  Theprintfunction is give to capture the logs, but any single argument function can be used.inner_planets=[planetforplanetinfind("$.star.planets.inner[*].name",solar_system,trace=log_to(print))]assertinner_planets==['Mercury','Venus','Earth','Mars']The results"""at $.star got {'name': 'Sun', 'dia...at $.star.planets got {'inner': [{'name': ...at $.star.planets.inner got [{'name': 'Mercury',...at $.star.planets.inner[*] got {'name': 'Mercury', ...at $.star.planets.inner[0].name got 'Mercury'at $.star.planets.inner[*] got {'name': 'Venus', 'N...at $.star.planets.inner[1].name got 'Venus'at $.star.planets.inner[*] got {'name': 'Earth', 'N...at $.star.planets.inner[2].name got 'Earth'at $.star.planets.inner[*] got {'name': 'Mars', 'Nu...at $.star.planets.inner[3].name got 'Mars'"""PathThe rootThe$point to root of the tree.value=get("$",solar_system)assertvalue==solar_systemIn a filter, the@point to the current element.value=get("$.star[?(@ == 'Sun')]",solar_system)assertvalue=='Sun'DictionariesKeysThe dictionary keys are referenced as dynamic attributes on a path.inner_from_attribute=get("$.star.planets.inner",solar_system)inner_from_string_keys=get("$.['star']['planets']['inner']",solar_system)assertinner_from_attribute==inner_from_string_keys==solar_system['star']['planets']['inner']Keys With Special CharactersDictionary keys that are not valid python syntax can be referenced as quoted strings.sun_equatorial_diameter=get("$.star.planets.inner[0]['Number of Moons']",solar_system)assertsun_equatorial_diameter==solar_system['star']['planets']['inner'][0]['Number of Moons']Wildcard as a Key.The * attribute specifies all sibling keys.   It is useful for iterating over attributes.star_children=[childforchildinfind("$.star.*",solar_system)]assertstar_children==[solar_system['star']['name'],solar_system['star']['diameter'],solar_system['star']["age"],solar_system['star']['planets'],]Comma Delimited KeysMultiple dictionary keys can be specified using a comma delimited list.last_and_first=[planetforplanetinfind("$.star['diameter', 'name']",solar_system)]assertlast_and_first==[1391016,"Sun"]ListIndexesList can be access using index.earth=get("$.star.planets.inner[2]",solar_system)assertearth==solar_system['star']['planets']['inner'][2]List the third inner and outer planet.last_two=[planetforplanetinfind("$.star.*.*[2].name",solar_system)]assertlast_two==['Earth','Uranus']Comma Delimited Indexes.List indexes can be specified as a comma delimited list.last_and_first=[planetforplanetinfind("$.star.planets.outer[3, 0].name",solar_system)]assertlast_and_first==["Neptune","Jupiter"]SlicesList can be access using slices.List the first two planets.first_two=[planetforplanetinfind("$.star.planets.outer[:2].name",solar_system)]assertfirst_two==["Jupiter","Saturn"]List the last two planets.last_two=[planetforplanetinfind("$.star.planets.outer[-2:].name",solar_system)]assertlast_two==["Uranus","Neptune"]List all outer planets in reverse.last_two=[planetforplanetinfind("$.star.planets.outer[::-1].name",solar_system)]assertlast_two==["Neptune","Uranus","Saturn","Jupiter"]List the last inner and outer planets.last_two=[planetforplanetinfind("$.star.*.*[-1:].name",solar_system)]assertlast_two==["Mars","Neptune"]Wildcard as an Index.The * token can be used as a list index.   It is useful for iterating over attributes.all_outer=[planetforplanetinfind("$.star.planets.outer[*].name",solar_system)]assertall_outer==["Jupiter","Saturn","Uranus","Neptune"]RecursionThe .. double dot implies recursive search.  It executes a preorder tree traversal.  The search algorithm
descends the tree hierarchy evaluating the path on each vertex until a match occurs.  On each iteration it
continues where it left off. This is an example that finds all the planets names.all_planets=[pforpinfind("$.star.planets..name",solar_system)]assertall_planets==['Mercury','Venus','Earth','Mars','Jupiter','Saturn','Uranus','Neptune']Here is another example that finds all the celestial bodies names.all_celestial_bodies=[pforpinfind("$..name",solar_system)]assertall_celestial_bodies==['Sun','Mercury','Venus','Earth','Mars','Jupiter','Saturn','Uranus','Neptune']FiltersFilters are use to add additional search criteria.filterThe ?() is a filter that evaluates a branched off path relative to its parent path.  This example
finds all celestial bodies that have planets.sun=get("$..[?(@.planets)].name",solar_system)assertsun=="Sun"This search finds all celestial bodies that have a has-moons attribute.all_celestial_bodies_moon_attribute=[planetforplanetinfind("$..[?(@['has-moons'])].name",solar_system)]assertall_celestial_bodies_moon_attribute==['Mercury','Venus','Earth','Mars','Jupiter','Saturn','Uranus','Neptune']This search finds all celestial bodies that have moons. Note theoperator.truthis used to exclude planets
that don't have moons.operator_truth=operator.truthall_celestial_bodies_moon_attribute=[planetforplanetinfind("$..[?(operator_truth(@['has-moons']))].name",solar_system,locals=locals())]assertall_celestial_bodies_moon_attribute==['Earth','Mars','Jupiter','Saturn','Uranus','Neptune']has filter comparison operatorsFilters can be specified with a comparison operator.earth=[planetforplanetinfind("$..[?(@.diameter == 12756)].name",solar_system)]assertearth==['Earth']earth=[planetforplanetinfind("$..[?(@.diameter != 12756)].name",solar_system)]assertearth==['Sun','Mercury','Venus','Mars','Jupiter','Saturn','Uranus','Neptune']earth=[planetforplanetinfind("$..[?(@.diameter > 12756)].name",solar_system)]assertearth==['Sun','Jupiter','Saturn','Uranus','Neptune']earth=[planetforplanetinfind("$..[?(@.diameter >= 12756)].name",solar_system)]assertearth==['Sun','Earth','Jupiter','Saturn','Uranus','Neptune']earth=[planetforplanetinfind("$..[?(@.diameter < 12756)].name",solar_system)]assertearth==['Mercury','Venus','Mars']earth=[planetforplanetinfind("$..[?(@.diameter <= 12756)].name",solar_system)]assertearth==['Mercury','Venus','Earth','Mars']There is also a regular expression operator.   This example finds
all the planets that end with the letter s.earth=[planetforplanetinfind(r"$..[?(@.name =~ '\w+s')].name",solar_system)]assertearth==['Venus','Mars','Uranus']has filter type conversionSometimes the value is the wrong type for the comparison operator. In this example the attribute
'Number of Moons' is str type.planets=[planetforplanetinfind("$..[?(@['Number of Moons'] > '5')].name",solar_system)]assertplanets==['Jupiter','Saturn']This is how to convert the type to an int before applying the comparison operator.planets=[planetforplanetinfind("$..[?(int(@['Number of Moons']) > 5)].name",solar_system)]assertplanets==['Jupiter','Saturn','Uranus','Neptune']has filter comparison operators as single argument functionsA filter operator can be specified as a single argument function.  Here an example that searches for planets that
have the same diameter as earth.earths_diameter=partial(operator.eq,12756)earth=[planetforplanetinfind("$..[?(earths_diameter(@.diameter))].name",solar_system,locals=locals())]assertearth==['Earth']Any single argument function can be used as an operator.  This example uses a Regular Expression to finds
planets that end with the letter s.name_ends_with_s=re.compile(r"\w+s").matchearth=[planetforplanetinfind("$..[?(name_ends_with_s(@.name))].name",solar_system,locals=locals())]assertearth==['Venus','Mars','Uranus']This example uses a closure to find planets that have the same diameter as earth.defsmaller_than_earth(value):returnvalue<12756earth=[planetforplanetinfind("$..[?(smaller_than_earth(@.diameter))].name",solar_system,locals=locals())]assertearth==['Mercury','Venus','Mars']logical and, or and not filtersandA regular express to test if the second letter in the value is 'a'.second_letter_is_a=re.compile(r".a.*").fullmatchTheandfunction evaluates as the logicalandoperator.   It is equivalent to: (arg1 and arg2 and ...)found=[planetforplanetinfind("$..[?(@.diameter < 10000 and (second_letter_is_a(@.name)))].name",solar_system,locals=locals())]assertfound==['Mars']orTheorfunction evaluates as the logicaloroperator.   It is equivalent to: (arg1 and arg2 and ...)found=[planetforplanetinfind("$..[?(@.diameter < 10000 or (second_letter_is_a(@.name)))].name",solar_system,locals=locals())]assertfound==['Mercury','Earth','Mars','Saturn']notThenotfunction evaluates as the logicalnotoperator.   It is equivalent to: (not arg)
This example find all the planets names not not equal to Earth.  Note the double nots.found=[planetforplanetinfind("$..[?(not (@.name != 'Earth'))].name",solar_system)]assertfound==['Earth']Combining has, and, or, and not filters.Each of thehasfunction can be passed as arguments to any of the otherhasfunction to construct complex
boolean equation.  This example is equivalent to:
(10000 > diameter  or diameter > 20000) and second_letter_is_a(name))found=[planetforplanetinfind("$..[?((@.diameter < 10000 or @.diameter > 20000) and (second_letter_is_a(@.name)))].name",solar_system,locals=locals())]assertfound==['Mars','Saturn']