From 237628f3f0cbe574d71559fa2ed7646d3cfb190e Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Thu, 21 May 2015 22:53:30 +0100 Subject: [PATCH] Provide a `sorted` operator This sorts (using python sorted) the current object's value if it is a list or dict and returns the list or keys. This is presented a strawman proposal for doing sorts as I couldn't decide how to do it correctly. At least with some starting code maybe we can reach something better. Note that the goal here is to get a sorted list of atomic entities which can be evalauted, not to sort a collection of objects by a key of those objects. That would be useful too, and presumably there is a way to do it generically. The demonstrated syntax is: foo.`sorted` presumably things like like: foo.[/] # ascending sort of this foo.[\] # descending sort of this foo.[/somekey] # ascending sort by somekey's value ought to be possible but I do not know if it is aligned with proper JSONPath. --- jsonpath_rw/jsonpath.py | 8 ++++++++ jsonpath_rw/parser.py | 2 ++ tests/test_jsonpath.py | 5 ++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/jsonpath_rw/jsonpath.py b/jsonpath_rw/jsonpath.py index 3c491d0..e68a76b 100644 --- a/jsonpath_rw/jsonpath.py +++ b/jsonpath_rw/jsonpath.py @@ -206,6 +206,14 @@ def __repr__(self): def __eq__(self, other): return isinstance(other, This) +class SortedThis(This): + + def find(self, datum): + """Return sorted value of This if list or dict.""" + if isinstance(datum.value, dict) or isinstance(datum.value, list): + return [DatumInContext.wrap(value) for value in sorted(datum.value)] + return datum + class Child(JSONPath): """ JSONPath that first matches the left, then the right. diff --git a/jsonpath_rw/parser.py b/jsonpath_rw/parser.py index fe5a6cb..1b7971d 100644 --- a/jsonpath_rw/parser.py +++ b/jsonpath_rw/parser.py @@ -95,6 +95,8 @@ def p_jsonpath_named_operator(self, p): "jsonpath : NAMED_OPERATOR" if p[1] == 'this': p[0] = This() + elif p[1] == 'sorted': + p[0] = SortedThis() elif p[1] == 'parent': p[0] = Parent() else: diff --git a/tests/test_jsonpath.py b/tests/test_jsonpath.py index bf3d5c6..2322a88 100644 --- a/tests/test_jsonpath.py +++ b/tests/test_jsonpath.py @@ -105,7 +105,10 @@ def test_fields_value(self): self.check_cases([ ('foo', {'foo': 'baz'}, ['baz']), ('foo,baz', {'foo': 1, 'baz': 2}, [1, 2]), ('@foo', {'@foo': 1}, [1]), - ('*', {'foo': 1, 'baz': 2}, set([1, 2])) ]) + ('*', {'foo': 1, 'baz': 2}, set([1, 2])), + ('objects.`sorted`', {'objects': ['alpha', 'gamma', 'beta']}, ['alpha', 'beta', 'gamma']), + ('objects.`sorted`', {'objects': {'cow': 'moo', 'horse': 'neigh', 'cat': 'meow'}}, ['cat', 'cow', 'horse']), + ]) jsonpath.auto_id_field = 'id' self.check_cases([ ('*', {'foo': 1, 'baz': 2}, set([1, 2, '`this`'])) ])