pythonjsonjsonpathjsonpath-ng

Adding a new node using jsonpath_ng


I would like to add a node to section of JSON after navigating to a particular section of it using jsonpath_ng as shown below:

import json
import jsonpath.ext as jspathExt
import pprint

jsStr = """
{
  "service_group": "default",
  "services": [
    {
      "service": "UserMgmt",
      "servers": [
        {
          "server": "ServerA",
          "ip_address": "192.168.1.1",
          "port": "80"
        },
        {
          "server": "ServerB",
          "ip_address": "192.168.1.2",
          "port": "80"
        }
      ]
    }
  ]
}
"""
js = json.loads(jsStr)

# create path
serviceName = "UserMgmt"
serverName = "ServerA"
pathExpr = f'$.services[?service="{serviceName}"].servers[?server = "{serverName}"]'
print(f"PathExpr: {pathExpr}")
serverExpr = jspathExt.parse(pathExpr)
m = serverExpr.find(js)
pprint.pprint(m[0].value)

This will give the following output: {'server': 'ServerA', 'ip_address': '192.168.1.1', 'port': '80'}

Now I want to be able to add {'action_status': 'Success'} to that node so that the output of: pprint.pprint(js) becomes the following:

{
  "service_group": "default",
  "services": [
    {
      "service": "UserMgmt",
      "servers": [
        {
          "server": "ServerA",
          "ip_address": "192.168.1.1",
          "port": "80",
          "action_status": "Success"       
        },
        {
          "server": "ServerB",
          "ip_address": "192.168.1.2",
          "port": "80"
        }
      ]
    }
  ]
}

I have looked at using the "update" method but couldn't get it to work. I'd appreciate any help you can provide.

Thanks,

Amit


Solution

  • Jsonpath-ng and its relatives have very sparse documentation, so there may be a better way of doing this, but this code should get you a little closer:

    m[0].value['action_status']='Success'
    items = str(m).split('context=DatumInContext(value=')
    final = items[-1].split(', path=Root(), context=None)))))]')[0]
    final_js = json.loads(final.replace("'",'"'))
    pprint.pprint(final_js)
    

    Output (not really that pretty...)

    {'service_group': 'default',
     'services': [{'servers': [{'action_status': 'Success',
                                'ip_address': '192.168.1.1',
                                'port': '80',
                                'server': 'ServerA'},
                               {'ip_address': '192.168.1.2',
                                'port': '80',
                                'server': 'ServerB'}],
                   'service': 'UserMgmt'}]}