Skip to content

How to modify the JSON #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
renard opened this issue Jan 21, 2015 · 15 comments
Open

How to modify the JSON #21

renard opened this issue Jan 21, 2015 · 15 comments

Comments

@renard
Copy link

renard commented Jan 21, 2015

Hi,

This seem to bee a promising lib for JSON parsing.

How can I modify a JSON structure given a path?

I would like to change:

{'foo': [{'baz': 1}, {'baz': 2}]}

to

{'foo': [{'baz': 3}, {'baz': 2}]}

Given a path: foo[0].baz

I tried:

>>> import jsonpath_rw
>>> json = {'foo': [{'baz': 1}, {'baz': 2}]}
>>> path = jsonpath_rw.parse(r'foo[0].baz')
>>> match = path.find(json)
>>> match
[DatumInContext(value=1, path=Fields('baz'), context=DatumInContext(value={'baz': 1}, path=<jsonpath_rw.jsonpath.Index object at 0x1095a7790>, context=DatumInContext(value=[{'baz': 1}, {'baz': 2}], path=Fields('foo'), context=DatumInContext(value={'foo': [{'baz': 1}, {'baz': 2}]}, path=This(), context=None))))]
>>> match[0].value
1
>>> match[0].value = 5
>>> json
{'foo': [{'baz': 1}, {'baz': 2}]}

I guess I missed something here.

thanks in advance.

Cheers

@renard
Copy link
Author

renard commented Jan 21, 2015

Finally I end up with something like that:

import jsonpath_rw

def get_path(match):
    '''return an iterator based upon MATCH.PATH. Each item is a path component,
start from outer most item.'''
    if match.context is not None:
        for path_element in get_path(match.context):
            yield path_element
        yield str(match.path)

def update_json(json, path, value):
    '''Update JSON dictionnary PATH with VALUE. Return updated JSON'''
    try:
        first = next(path)
        # check if item is an array
        if first.startswith('[') and first.endswith(']'):
            try:
                first = int(first[1:-1])
            except ValueError:
                pass
        json[first] = update_json(json[first], path, value)
        return json
    except StopIteration:
        return value


json = {'foo': [{'baz': 1}, {'baz': 2}], 'bar': { 'just': 'a', 'dict': 'object'}}
path = jsonpath_rw.parse(r'*.just')
matches = path.find(json)

print json
for match in matches:
    full_path = '/'.join(get_path(match))
    json = update_json(json, get_path(match), full_path)
print json
{'foo': [{'baz': 1}, {'baz': 2}], 'bar': {'dict': 'object', 'just': 'a'}}
{'foo': [{'baz': 1}, {'baz': 2}], 'bar': {'dict': 'object', 'just': 'bar/just'}}

Maybe this could be a feature for jsonpath_rw.

@kennknowles
Copy link
Owner

Hello! This is a good point. It is actually where the "rw" in the name of the package comes from: read/write. But I got distracted. The intended design is immutable update:

data = ...
pattern = jsonpath_rw.parse('*.just')
new_data = pattern.update(data, lambda x: ...)
more_new_data = pattern.set(data, "some value")
even_more_new_data = pattern.contextual_update(data, lambda context, x: ...)

There are many useful ways to update:

  • A function from old value to new value.
  • A constant value to be set (degenerate form of the above).
  • A function from old value and some context information to new value.

Pull requests welcome :-)

@ailjushkin
Copy link
Collaborator

@renard
@kennknowles
@gera
@iley
@hakanw

I'm also have to use such method. How can I change values using jsonpath?

@petr0ff
Copy link

petr0ff commented Jan 18, 2016

Hi! Is there any progress on it? :) I'm getting Not implemented error, when trying to use jsonpath_expr.update(my_json, "some_value")

@ailjushkin
Copy link
Collaborator

There is a way to update json, but it is not documented and wrapped into a
function. I will post sample code little bit later.

пн, 18 янв. 2016, 15:40, petr0ff [email protected]:

Hi! Is there any progress on it? :) I'm getting Not implemented error,
when trying to use jsonpath_expr.update(my_json, "some_value")


Reply to this email directly or view it on GitHub
#21 (comment)
.

@petr0ff
Copy link

petr0ff commented Jan 18, 2016

Nice, thanks! Actually I've tried @renard 's solution and it worked for me

@ailjushkin
Copy link
Collaborator

@petr0ff well, as I can see from PC now, joshbenner have implemented the normal update method (#28).

But just in case if someone could be interested, I post here my solution:

def string_to_json (self, source):
    try:
        load_input_json=json.loads(source)
    except ValueError, e:
        raise Exception("Could not parse '%s' as JSON: %s"%(source, e))
    return    load_input_json

def update_json(self, json_string, expr, value, index=0):
     load_input_json=self.string_to_json (json_string)
     matches = self._json_path_search(load_input_json, expr)
     datum_object = matches[int(index)]
     if not isinstance(datum_object, DatumInContext):
         raise Exception("Nothing found by the given json-path")
     path = datum_object.path
     if isinstance(path, Index):
         datum_object.context.value[datum_object.path.index] = value
     elif isinstance(path, Fields):
         datum_object.context.value[datum_object.path.fields[0]] = value

     return load_input_json

@cliffpracht
Copy link

cliffpracht commented Aug 30, 2016

@PositiveAlex, How are you using this without changing anything? I don't see _json_path_search defined anywhere. Are you inheriting another class from this?
Thanks.

@impredicative
Copy link

impredicative commented Aug 16, 2017

This allows updates with the jsonpath-ng package, but I still don't have a way to delete keys!

@namratha-bharadwaj
Copy link

namratha-bharadwaj commented Sep 20, 2018

Hi... I have been looking for a solution to this too
Can someone please help me with the full solution to this?
@ailjushkin what's the method definition of "_json_path_search(load_input_json, expr)"?
Is it taking the json_object and the jsonPath in string format, and returning the jsonpath_expr?
also, what are "Index" and "Fields" in lines "if isinstance(path, Index):" and "elif isinstance(path, Fields):"

@ulidtko
Copy link

ulidtko commented Oct 11, 2019

Hey @kennknowles,

The intended design is immutable update:

data = ...
pattern = jsonpath_rw.parse('*.just')
new_data = pattern.update(data, lambda x: ...)
more_new_data = pattern.set(data, "some value")

This is indeed very nice, but would you care to release this functionality? It's available in master branch only; the latest release 1.4.0 lacks the code.

It's not that pip install https://github.com/kennknowles/python-jsonpath-rw doesn't work; rather, it's the "unfinished code in flux" status that's communicated by installing from master.

@ulidtko
Copy link

ulidtko commented Oct 11, 2019

Ah, I see. They already implemented this, in a fork.

Switch to https://github.com/h2non/jsonpath-ng

@ailjushkin
Copy link
Collaborator

Hi, maybe it is better to close all issues here and change readme that this repo is deprecated.

@kennknowles
Copy link
Owner

Hi all. It is true that I have no time to maintain this or even really do code review. I am happy to merge a pull request that makes the README point to a newer fork.

@ulidtko
Copy link

ulidtko commented Oct 22, 2019

Hi all. It is true that I have no time to maintain this or even really do code review. I am happy to merge a pull request that makes the README point to a newer fork.

Hey, can you please merge #76 ?

Pointing to a newer fork is not really a good way out... Finding a new maintainer and giving them GitHub + PyPi access is. Still, your being around and responding is appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants