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"]

4
  • 1
    This would be a little less confusing among other things if you don't overwrite builtin keywords like str Commented May 15, 2020 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). Commented May 15, 2020 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. Commented May 15, 2020 at 14:45
  • In general, you should avoid the eval method (stackoverflow.com/questions/1832940/…). 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 (stackoverflow.com/questions/15197673/…) Commented May 15, 2020 at 14:51

1 Answer 1

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}')
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.