title: Find and modify python nested dictionary (key, value)
body: <p>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.</p>
  
  <p>Ultimatley I want to be able to perfom Create/Delete action in addition to the update. </p>
  
  <hr>
  
  <h2>Here is the script and input file.</h2>
  
  <pre><code># 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.
          &gt;&gt;&gt; to_path('foo')
          ['foo']
          &gt;&gt;&gt; to_path('foo.bar')
          ['foo', 'bar']
          &gt;&gt;&gt; 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()
  </code></pre>
  
  <hr>
  
  <pre><code>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"
          }
        ]
      }
    ]
  }
  </code></pre>
  
  <p>Credit goes to original author: Vincent Driessen</p>