1

I have this Json as string:

json_String= {
    "type": [
        {
            "color": "blue",
            "contrast": "high",
            "stock": "enough"
        },
        {
            "color": "orange",
            "contrast": "high",
            "stock": "enough",
            "details": "noneTobeGiven"
        },
        {
            "color": "red",
            "contrast": "low",
            "stock": "enough",
            "details": "noneTobeGiven"
        },
        {
            "color": "blue",
            "contrast": "high",
            "stock": "enough",
            "details": "noneTobeGiven"
        }
    ]
}

creating a dict from it:

dict1 = eval(json_String)

Based on this answer I'm tring to return all the occurances of a tag for a specific path

from functools import reduce  # forward compatibility for Python 3
import operator

def get_by_path(root, items):
    """Access a nested object in root by item sequence."""
    return reduce(operator.getitem, items, root)


print(get_by_path(dict1, ["type", "color"]))

But an error is received :

TypeError: list indices must be integers or slices, not str

I assume this is because of the list and it expects an index instead of str, and tried to call the module as such :

print(get_by_path(dict1, ["type", "color"][0]))

The result was :

    return reduce(operator.getitem, items, root)

KeyError: 't'

Goal

For a given path, lets say type.color, to return all the values for [color] for every occurance:

print(get_values_by_path("type.color")

["blue", "orange", "red", "blue"]

Henry-G
  • 131
  • 1
  • 8
  • 1
    This would be a little less confusing among other things if you don't overwrite builtin keywords like `str` – Jab May 15 '20 at 14:42
  • Use `json.loads` to parse JSON, not `eval`, that's what it's for. And you have a typo - you're applying the index `[0]` to `["type", "color"]`, **not** `dict1` (which is actually a list). – jonrsharpe May 15 '20 at 14:43
  • You're right about the list causing problems. If you're not set on implementing this yourself, there are libraries like jmespath, jsonpath, objectpath that do just this. – chash May 15 '20 at 14:45
  • In general, you should avoid the ``eval`` method (https://stackoverflow.com/questions/1832940/why-is-using-eval-a-bad-practice). It is considered a bad, insecure practice. If you want to retrieve an object's type based on its literal, it is saver to use ``literal_eval `` from the ast module (https://stackoverflow.com/questions/15197673/using-pythons-eval-vs-ast-literal-eval) – dheinz May 15 '20 at 14:51

1 Answers1

1
from jsonpath_ng import jsonpath, parse
import json


json_data = json.loads(Json string from the description above)


print(json_data)

jsonpath_expression = parse('type[*].color')

for match in jsonpath_expression.find(json_data):
    print(f' Color: {match.value}')
Henry-G
  • 131
  • 1
  • 8