skip to Main Content

Hi I need help to create a new list from looping through JSON output file "ruletree"

ruletree = {
    "account": "act_F-AC-1234",
    "contract": "ctr_F-1234",
    "propertyName": "www.domain.com",
    "rules": {
        "name": "default",
        "children": [
            {
                "name": "Route One",
                "children": [],
                "behaviors": [
                    {
                        "name": "origin",
                        "options": {
                            "originType": "CUSTOMER",
                            "hostname": "first.gateway.com",
                        },
                    }
                ],
            },
            {
                "name": "Route Two",
                "children": [],
                "behaviors": [
                    {
                        "name": "origin",
                        "options": {
                            "originType": "CUSTOMER",
                            "hostname": "second.gateway.com",
                        },
                    }
                ],
            },
        ],
    },
}

my code looks like this, getting error "TypeError: list indices must be integers or slices, not str"

hostnames = []
for host in ruletree['rules']['children']['behaviors']['options']:
  options.get('hostname', N/A)
  hostnames.append(host)
  print(hostnames) 

expected output

{"propertyName": "www.domain.com", "hostnames": "first.gateway.com, second.gateway.com"}

3

Answers


  1. You missed that children and behaviors are lists, not dictionaries, so you can’t use string indices to fetch their values.

    Fixed your code as follows:

    hostnames = []
    for child in ruletree['rules']['children']:
        for behavior in child['behaviors']:
            host = behavior['options'].get('hostname', 'N/A')
            hostnames.append(host)
            
    print(hostnames)
    

    Output:

    ['first.gateway.com', 'second.gateway.com']
    
    Login or Signup to reply.
  2. so this error means that in a list, you are trying to index using a string.
    Here’s an example

    a = [1, 2, 3]
    # You want the index 1(2nd element)
    second_element = a[2]
    # But if you give, a["2"] or something else, a["abdjsk"], it'll give the error you are getting.
    

    As per your output json file, that error is coming because ruletree[rules][children] is a list.

    So, you need to iterate this as well.
    Another issue I see is you are using options.get but the iterating variable is host, so even if you iterate right, your iterating variable was wrong, so that needs to be corrected as well.
    Here’s the correct code

    result = session.get(urljoin(baseurl, path), headers=headers, params=querystring, verify=False)
    ruletree = result.json()
    
    hostnames = []
    for child in ruletree['rules']['children']:
      for behaviour in child["behaviors"]:
        options = behaviour["options"]
        hostnames.append(options.get("hostname", "N/A"))
      
            
    print(hostnames)
    
    Login or Signup to reply.
  3. @Zero has already identified and solved your problem.

    However, if you’re spending much time parsing and querying json, it could be useful to be aware of the jmespath package.

    With jmespath you could extract your hostnames as:

    import jmespath
    
    jmespath.search("rules.children[].behaviors[].options[].hostname", ruletree)
    
    # output: ["first.gateway.com", "second.gateway.com"]
    

    Additionally, one could go further and create your full desired output:

    {
        "propertyName": "www.domain.com",
        "hostnames": ["first.gateway.com", "second.gateway.com"],
    }
    

    with:

    jmespath.search(
        """{
            propertyName: propertyName,
            hostnames: rules.children[].behaviors[].options[].hostname
        }""",
        ruletree
    )
    
    # output: {"propertyName": "www.domain.com", "hostnames": ["first.gateway.com", "second.gateway.com"]}
    

    Edit: desired output of OP has changed.

    If you created a list of hostnames, you can make it into a comma separated string with ", ".join(hostnames).

    Alternatively, if you are opting for a jmespath approach:

    jmespath.search("join(', ', rules.children[].behaviors[].options[].hostname)", ruletree)
    
    # output: "irst.gateway.com, second.gateway.com"
    

    or for the full output in a single go:

    jmespath.search(
        """{
            propertyName: propertyName,
            hostnames: join(', ', rules.children[].behaviors[].options[].hostname)
        }""",
        ruletree
    )
    
    # output: {"propertyName": "www.domain.com", "hostnames": "first.gateway.com, second.gateway.com"}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search