循环遍历JSON输出文件以获取特定键和值。

huangapple go评论67阅读模式
英文:

Loop through JSON output file to get specific keys and values

问题

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

output = {
    "propertyName": ruletree["propertyName"],
    "hostnames": ", ".join(hostnames)
}

output
英文:

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

答案1

得分: 5

你错过了childrenbehaviors是列表,而不是字典,所以你不能使用字符串索引来获取它们的值。

修复了你的代码如下:

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

print(hostnames)

输出:

['first.gateway.com', 'second.gateway.com']
英文:

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

答案2

得分: 1

这个错误意味着在一个列表中,你尝试使用字符串进行索引。

这里有一个例子:

a = [1, 2, 3]
# 你想要索引1(第二个元素)
第二个元素 = a[2]
# 但如果你尝试a["2"]或其他任何字符串,比如a["abdjsk"],就会出现你得到的错误。

根据你的输出 JSON 文件,这个错误是因为 ruletree[rules][children] 是一个列表。

因此,你也需要对它进行迭代。我还注意到另一个问题,你在使用 options.get 时,迭代变量是 host,所以即使你迭代正确,你的迭代变量也是错误的,这也需要纠正。下面是正确的代码:

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)
英文:

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)

答案3

得分: 1

@Zero 已经识别并解决了你的问题。

然而,如果你花费大量时间解析和查询 JSON,了解 jmespath 包可能会很有用。

使用 jmespath,你可以提取主机名如下:

import jmespath

jmespath.search("rules.children[].behaviors[].options[].hostname", ruletree)

# 输出: ["first.gateway.com", "second.gateway.com"]

此外,你还可以进一步创建你所需的完整输出:

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

使用以下代码实现:

jmespath.search(
    """{
        propertyName: propertyName,
        hostnames: rules.children[].behaviors[].options[].hostname
    }""",
    ruletree
)

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

编辑: OP 的期望输出已更改。

如果你已经创建了一个主机名列表,你可以使用 ", ".join(hostnames) 将其转换为逗号分隔的字符串。

或者,如果你选择使用 jmespath 方法:

jmespath.search("join(', ', rules.children[].behaviors[].options[].hostname)", ruletree)

# 输出: "first.gateway.com, second.gateway.com"

或者一次性获取完整输出:

jmespath.search(
    """{
        propertyName: propertyName,
        hostnames: join(', ', rules.children[].behaviors[].options[].hostname)
    }""",
    ruletree
)

# 输出: {"propertyName": "www.domain.com", "hostnames": "first.gateway.com, second.gateway.com"}
英文:

@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"}

huangapple
  • 本文由 发表于 2023年7月3日 14:32:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/76602326.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定