查找和修改python嵌套字典(键,值)

时间:2016-07-25 20:39:37

标签: python json dictionary

我有一个需要更新的json文件。我正在将它转换为python dict(嵌套)来更新它。这是输入,但它可以是任何部门。我确信有更好的方法可以做到这一点,但不知道。

Ultimatley除了更新之外,我希望能够执行创建/删除操作。

这是脚本和输入文件。

# Now find TARGET value in nested key value chain

# Replace old value with NEWVALUE

import json
from pprint import pprint
d1 = open('jinputstack.json', 'r')
d1 = json.load(d1)

def traverse(obj, path=None, callback=None):
    """
    Traverse Python object structure, calling a callback function for every element in the structure,
    and inserting the return value of the callback as the new value.
    """
    if path is None:
        path = []

    if isinstance(obj, dict):
        value = {k: traverse(v, path + [k], callback)
                 for k, v in obj.items()}
    elif isinstance(obj, list):
        value = [traverse(elem, path + [[]], callback)
                 for elem in obj]
    else:
        value = obj

    if callback is None:
        # print("Starting value Found-----------------------------------------------------")
        print(value)
        return value

    else:
        print(path, value)
        return callback(path, value)


def traverse_modify(obj, target_path, action):
    """
    Traverses any arbitrary object structure and performs the given action on the value, 
    replacing the node with the
    action's return value.
    """
    target_path = to_path(target_path)
    pprint(value)
    pprint(target_path)

    def transformer(path, value):
        if path == target_path:
            print(action)
            d2 = data["groups"][0]["properties"][1]["value"]["data"][2]["object"]["name"].update(action)
            return d2

        else:
            return value

    return traverse(obj, callback=transformer)


def to_path(path):
    """
    Helper function, converting path strings into path lists.
        >>> to_path('foo')
        ['foo']
        >>> to_path('foo.bar')
        ['foo', 'bar']
        >>> to_path('foo.bar[]')
        ['foo', 'bar', []]
    """
    if isinstance(path, list):
        return path  # already in list format

    def _iter_path(path):

        #pprint(path.split)

        for parts in path.split('[]'):
            for part in parts.strip('.').split('.'):
                yield part
            yield []

    return list(_iter_path(path))[:-1]

def updateit(newvalue):

    data["groups"][0]["properties"][1]["value"]["data"][2]["object"]["name"] = newvalue 
    print(data["groups"][0]["properties"][1]["value"]["data"][2]["object"]["name"])
    return data["groups"][0]["properties"][1]["value"]["data"][2]["object"]["name"]

traverse_modify(d1, d1["groups"][0]["properties"][1]["value"]["data"][1]["object"]["name"], updateit("XXXXXXXXXXXXXX"))

json_data = json.dumps(data)

f = open("jinputstack.json","w")
f.write(json_data)
f.close()
jinputstack.json = {
  "groups": [
    {
      "name": "group1",
      "properties": [
        {
          "name": "Test-Key-String",
          "value": {
            "type": "String",
            "encoding": "utf-8",
            "data": "value1"
          }
        },
        {
          "name": "Test-Key-ValueArray",
          "value": {
            "type": "ValueArray",
            "data": [
              {
                "data": true
              },
              {
                "type": "Blob",
                "object": {
                  "name": "John Su",
                  "age": 25,
                  "salary": 104000.45,
                  "married": false,
                  "gender": "Male"
                }
              }
            ]
          }
        }
      ],
      "groups": [
        {
          "name": "group-child",
          "properties": [
            {
              "name": "Test-Key-String"
            },
            {
              "name": "Test-Key-List",
              "value": {
                "type": "List",
                "data": [
                  "String1",
                  "String2",
                  "String3"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "group2",
      "properties": [
        {
          "name": "Test-Key2-String",
          "value": {
            "type": "String",
            "encoding": "utf-8",
            "data": "value2"
          }
        },
        {
          "name": "MicroBox"
        }
      ]
    }
  ]
}

归功于原作者:Vincent Driessen

1 个答案:

答案 0 :(得分:1)

我认为最好的方法是将Json对象转换为XML并使用ElementTree和XPath来解析和修改对象。之后,如果需要,您可以恢复为Json:

import json
from xmljson import parker
from lxml.etree import Element

dataxml = parker.etree(datajson, root=Element('root'))
print(dataxml.find('.//data//name').text)            # John Su
dataxml.find('.//data//name').text = "Joan d'Arc"
print(dataxml.find('.//data//name').text)            # Joan d'Arc
print(json.dumps(parker.data(dataxml)))

有些软件包直接在Json字符串上执行类似XPath的操作。其中之一,jsonpath-rw更改了语法。我更喜欢坚持使用标准的XPath语法。

from jsonpath_rw import jsonpath, parse

expr = parse('$..data..name')   # Notice that . is now $ and / is now .
                                # Confusing enough?
expr.find(datajson)[0] = 'yyyy'
print(expr.find(datajson)[0].value)                  # John Su

另一个xjpath非常简单,也许更容易学习,与你现在所做的相比并没有太大的差别。

import xjpath

xj = xjpath.XJPath(datajson)
print(xj['groups.@0.properties.@1.value.data.@1.object.name'])

# Not much different than your code:
print(data["groups"][0]["properties"][1]["value"]["data"][1]["object"]["name"])

我希望这会有所帮助。