根据键值将路径存储到“ @myID”

时间:2019-08-06 12:09:14

标签: python json parsing

我有以下格式的json。

 json_tree ={
  "Garden": {
    "Seaside": {
      "@loc": "127.0.0.1",
      "@myID": "1.3.1",
      "Shoreside": {
        "@myID": "3",
        "InfoList": {
          "Notes": {
            "@code": "0",
            "@myID": "1"
          },
          "Count": {
            "@myID": "2",
            "@val": "0"
          }
        },
        "state": "0",
        "Tid": "3",
        "Lakesshore": {
          "@myID": "4",
          "InfoList": {
            "Notes": {
              "@code": "0",
              "@oid": "1"
            },
            "Count": {
              "@myID": "2",
              "@val": "0"
            }
          },
          "state": "0",
          "Tid": "4"
        }
      },
      "state": "0",
      "Tid": "2"
    },
    "Tid": "1",
    "state": "0"
  }
}

我的实现:

def getmyID(json_tree, itemList):
    for k1, v1 in json_tree .items():
        for k,v in v1.items():
            if k == itemList:
                return '{}{}.{}'.format(json_tree['@myID'] + '.' if '@myID' in json_tree else '',
                                            v['@myID'], v['InfoList']['status']['@myID'])   

我的问题是,当我要查找到“ BackYard”的路线时,此方法返回“ None”时不起作用。请注意,“后院”嵌套在“海边”节点内。

我将关键节点的“ @myID”附加到相应“状态”节点中的“ @myID”上。

getmyID(json_tree, "Seaside")
"Output" = "1.2.3.26" --> Currently I get this only

getmyID(json_tree, "BackYard")
"Output" = "1.2.3.75.32" --> expected output but getting "None"
The expected output of "Backyard" is created by concatenating the "@myID" of the root node which it is nested in, that is "Seaside" in this case, and concatenating it with the "@myID" of "backYard" and the "@myID" of its "status" node. 

"For a nested node, output string is formed by":

["root @myID" + "nested node "@myID" + "status node @myID"] or ["1.2.3" + "75" + "23"] for "Backyard".
"For a level node, output string is formed by":
["root @myID" + "status node @myID"] or ["1.2.3" + "26"] for "Seaside".

任何帮助将不胜感激。 谢谢。

2 个答案:

答案 0 :(得分:1)

您可以将递归与生成器一起使用:

def get_vals(d, target, path = []):
   for a, b in d.items():
      if a == target:
         yield '.'.join(filter(None, path+[b['@myID'], b["InfoList"]['status']['@myID']]))
      if isinstance(b, dict):
         yield from get_vals(b, target, path + [b.get('@myID', '')])


print(list(get_vals(json_tree, "Seaside")))
print(list(get_vals(json_tree, "BackYard")))

输出:

['1.2.3.26']
['1.2.3.75.32']

编辑:最新数据:

def get_vals(d, target, paths = []):
  for a, b in d.items():
    if a == target:
      yield '.'.join(filter(None, paths+[b["@myID"], b.get("InfoList", {}).get('Notes', {}).get('@myID')]))
    if isinstance(b, dict):
      yield from get_vals(b, target, paths+[b.get('@myID')])

print(list(get_vals(json_tree, "Seaside")))
print(list(get_vals(json_tree, 'Shoreside')))

输出:

['1.3.1']
['1.3.1.3.1']

答案 1 :(得分:-2)

编辑-只要人们告诉我原因,人们对我的答案不满意甚至编辑都不会有问题。很想听听Yvette Colomb和ChrisF的回音。

这是我使用基于堆栈的方法提出的解决方案。这样做的想法是,在找到所需的键(称为itemList)之前,尝试深入嵌套结构。我确定必须有更简单的方法:

json_tree = {
    "Gardens": {
        "Seaside": {
            "@loc": "porch",
            "@myID": "1.2.3",
            "Tid": "1",
            "InfoList": {
                "status": {
                    "@default": "0",
                    "@myID": "26"
                },
                "count": {
                    "@default": "0",
                    "@myID": "1"
                }
            },
            "BackYard": {
                "@myID": "75",
                "Tid": "2",
                "InfoList": {
                    "status": {
                        "@default": "6",
                        "@myID": "32"
                    },
                    "count": {
                        "@default": "0",
                        "@myID": "2"
                    }
                }
            }
        }
    }
}


def is_valid_kv_pair(key, value):
    try:
        assert isinstance(key, str)
        assert isinstance(value, dict)
        assert isinstance(value["@myID"], str)
        assert isinstance(value["Tid"], str)
        assert isinstance(value["InfoList"], dict)
        assert isinstance(value["InfoList"]["status"], dict)
        assert isinstance(value["InfoList"]["status"]["@default"], str)
        assert isinstance(value["InfoList"]["status"]["@myID"], str)
    except (AssertionError, KeyError):
        return False
    else:
        return True


def get_id(dictionary, desired_key):

    if not isinstance(dictionary, dict):
        return None

    dictionary_stack = [dictionary]
    root_stack = []
    while dictionary_stack:
        current_dictionary = dictionary_stack.pop()
        appended_root = False
        for key, value in current_dictionary.items():
            if appended_root:
                root_stack.pop()
            if is_valid_kv_pair(key, value):
                if key == desired_key:
                    rootIDs = [d["@myID"] for d in root_stack]
                    myID = value["@myID"]
                    statusID = value["InfoList"]["status"]["@myID"]
                    return ".".join(rootIDs + [myID] + [statusID])
                root_stack.append(value)
                appended_root = True
            if isinstance(value, dict):
                dictionary_stack.append(value)

    return None


ID = get_id(json_tree, "BackYard")
print(ID)