sakstig

SakStig is an objectpath implementation that uses proper querysets and supports querying any python object that supports the dict or list interfaces

View on GitHub

SakStig follows the semantics of objectpath for the expressions themselves. However, it deviates at the Python API level as well as philosophically by operating on (and returning) querysets instead of individual objects.

A QuerySet is simply a list of (intermediate) query results. At each step of the query execution, a QuerySet is processed, creating a new QuerySet. The operation might be to just filter the QuerySet, or to map entries into say their children, or to form a new QuerySet containing all the children of all the elements of the previous QuerySet.

import sakstig
results = sakstig.QuerySet([my_data]).execute("$.store.book.*[@.price > 4].title")
for result in results:
    print result

As can be seen above, not only does a query return a QuerySet, it also takes one as input, meaning the first thing you have to do when using SakStig is to construct a QuerySet.

Note that while a QuerySet inherits from the python list type, it isn’t to be seen as a list. In particular, if your query matches a single node in your data that is a list, execute() will return a QuerySet with one element that is that list. Warning: This is different from other objectpath implementations!

Extracting items from QuerySets and turning QuerySets into lists

List items can be extracted into a QuerySet using the * operator. MyList.* will return a QuerySet holding all items from all lists in the QuerySet MyList.

A QuerySet can be turned into a list, and returned as a single item inside a new QuerySet using the normal list constructor operation. [MyQuerySet] will return a QuerySet containing a single list, which in turn contains as its items all items in the QuerySet MyQuerySet.

QuerySet union

SakStig supports an extension to the ObjectPath syntax to merge QuerySets. The , operator takes two expressions and forms the union of their reults. Note that in a function argument, array or dictionary context, you must surround this type of expression by parenthesis as it would otherwize be ambigous.

Additional functions

SakStig supports some additional functions as well as some additional usages of existing functions beyond what ObjectPath does:

>>> sakstig.QuerySet([["a", "b", "c", "d"]]).execute("slice($, [1,None])")
['b', 'c', 'd']
>>> sakstig.QuerySet([[{"a":1, "b":2}, {"a":1, "b":1}, {"a":2, "b":2}]]).execute("sort($, @.a + @.b)")
[{'a': 1, 'b': 1}, {'a': 1, 'b': 2}, {'a': 2, 'b': 2}]
>>> sakstig.QuerySet([[1, 2, 3]]).execute("map(@+1, $)")
[2, 3, 4]
>>> sakstig.QuerySet([[1, 2, 3, 4]]).execute("reduce($, @[0] * @[1])")
24