Sum
Sum

Reputation: 363

How to extract multiple json values from a nested json response using python

My test url returns below json response: a={ "version": "1.3.0", "services": [ { "version": "1.0.0", "serviceGun": "com.xx.version.1", "description": "test service", "links": [ { "rel": "capabilities", "href": "/abc/test", "hints": [ { "method": "get" } ]

    },
{
    "version": "1.0.0",
    "serviceGun": "com.xx.abx.version.1",
    "description": "mode",
    "links": [ 
    {
        "rel": "mediaConfiguration",
        "href": "/abc/rest",
        "hints": [ 
        {
            "method": "get"

        },
        {
            "method": "put"
        } ]

    },
    {
        "rel": "modeConfiguration",
        "href": "/abc/mode",
        "hints": [ 
        {
            "method": "get"

        },
        {
            "method": "put"
        } ]

    },

{
    "version": "1.0.0",
    "serviceGun": "com.xx.abc.version.1",
    "description": "controlPanel",
    "links": [ 
    {
        "rel": "configuration",
        "href": "/abc/controlPanel",
        "hints": [ 
        {
            "method": "get"

        },
        {
            "method": "put"
        } ]

    },
    {
        "rel": "state",
        "href": "/abc/awc",
        "state": "unavailable",
        "stateReason": "inactivated",
        "hints": [ 
        {
            "method": "get"
        } ]
    } ]

},
 ]

}

With below function I am able to retrieve single value from json (e.g href,rel etc). But I want the function to return a list which has all "href" with supporting methods in "hints" for each href. e.g : [(href1,hints1),(href1,hints1),(href1,hints1)]

Expected output : [('/abc/test',['get','put']),('/abc/rest',['get','put']),...]

def extract_values(obj, key): """Pull all values of specified key from nested JSON.""" arr = []

def extract(obj, arr, key):
    """Recursively search for values of key in JSON tree."""
    if isinstance(obj, dict):
        for k, v in obj.items():
            if isinstance(v, (dict, list)):
                extract(v, arr, key)
            elif k == key:
                arr.append(v)
    elif isinstance(obj, list):
        for item in obj:
            extract(item, arr, key)
    return arr

results = extract(obj, arr, key)
return results

Run : test_ref = extract_values(a,'href') print test_ref Output : ['/abc/test','/abc/rest',','/abc/mode','/abc/controlPanel','abc/awc']

Expected Output : [('/abc/test',['get','put']),('/abc/rest',['get','put']),...]

Upvotes: 0

Views: 216

Answers (1)

BurningKarl
BurningKarl

Reputation: 1196

I think your recursion tries to solve a problem that does not exist. Your JSON has a hierarchical structure that is clearly visible.

  1. a['services'] is a list of services
  2. a['services'][i]['links'] is the list of links of ith service
  3. a['services'][i]['links'][j]['href'] is the URL of the jth link of the ith service

So my function would look like this:

def parse_links_and_methods(json_result):
    for service in json_result['services']:
        for link in service['links']:
            for hint in link['hints']:
                if 'method' in hint:
                    yield link['href'], hint['method']

This is basically just one huge list comprehension. You would use it as:

print list(parse_links_and_methods(a))

and get [('/abc/test', 'get'), ('/abc/rest', 'get'), ('/abc/rest', 'put'), ('/abc/mode', 'get'), ('/abc/mode', 'put'), ...]

EDIT I misread your expected output. To have it the way you want it use

def parse_links_and_methods(json_result):
    for service in json_result['services']:
        for link in service['links']:
            methods = [hint['method'] for hint in link['hints']
                       if 'method' in hint]
            yield link['href'], methods

Upvotes: 1

Related Questions