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

时间:2022-04-19 18:12:50

I have a json file that I need to update. I am converting it to a python dict (nested) to update it. Here is the input, but it could be any dept. I'm sure there is a better way to do this, but don't know.

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

Ultimatley I want to be able to perfom Create/Delete action in addition to the update.

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


Here is the script and input file.

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

Credit goes to original author: Vincent Driessen

归功于原作者:Vincent Driessen

1 个解决方案

#1


1  

I think the best way would be to convert the Json object to XML and use ElementTree and XPath to parse and modify your object. Later you can revert to Json if you need:

我认为最好的方法是将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)))

There are some packages that do something like XPath on a Json string directly. One of them, jsonpath-rw changes the syntax. I prefer to stick with the standard XPath syntax.

有些软件包直接在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

Another one xjpath very simple and perhaps easier to learn, does not give you much difference than what you are doing now.

另一个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"])

I hope this helps.

我希望这有帮助。

#1


1  

I think the best way would be to convert the Json object to XML and use ElementTree and XPath to parse and modify your object. Later you can revert to Json if you need:

我认为最好的方法是将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)))

There are some packages that do something like XPath on a Json string directly. One of them, jsonpath-rw changes the syntax. I prefer to stick with the standard XPath syntax.

有些软件包直接在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

Another one xjpath very simple and perhaps easier to learn, does not give you much difference than what you are doing now.

另一个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"])

I hope this helps.

我希望这有帮助。