pynspect.jpath module¶
This module provides tools for parsing JPaths and setting or retrieving values on given JPath within data structures.
JPath is simplified version of JSONPath and can be used to addressing nodes within arbitrary data structure composed of dict-like and list-like objects. Basically it can be used for any data structure of objects implementing Python 3 list and/or dict interface.
The motivation for implementing this module were following two use cases:
Enable writing of simple rules in various filtering expressions, for example:
Source.IP4 in [192.168.0.0/24, 192.168.0.0/24]
Enable simple message modifications based on key => value rules, for example:
"Source[1].Type[*]" = "source type tag"
The obvious first choice for a solution was the jsonpath-rw library. The full JSONPath however seems to be too big of a gun for our needs and in some cases it could even enable users to cut the branch they are sitting on. For this reason we have designed this simplified version with only required set of basic features.
JPath syntax uses only dot characters .
as node delimiters. Each node name may
contain only one or more of the following characters:
[a-zA-Z0-9_]+
Node delimiters implicitly work with nested dictionaries and using delimiter results in appending new dictionary as a value of given key in parent disctionary. Working with lists is enabled by using indices. List indices must be enclosed in brackets ‘[‘ and ‘]’ and may contain one of the following values:
[int]
- precise index (negative values not permitted, numbering starts with 1)[#]
- last (because you might not know number of nodes)[*]
- all nodes(index omitted)
When retrieving value(s) at given JPath, use of indices will have following effects:
[int]
- Return node at particular list position (starting with 1)[#]
- Return last node[*]
- Return all nodes (same as omitting)(index omitted) - Return all nodes (same as ‘*’)
When setting value(s) to given JPath, use of indices will have following effects:
[int]
- Set value to particular list node (starting with 1)[#]
- Set value to already existing last node, or append new one to an empty list[*]
- Append new value to a list(index omitted) - This will result in a dictionary key instead of a list
Consider following examples:
>>> msg = {
'Format': 'IDEA0',
'ID': 'MESSAGE_ID',
'DetectTime': 'DETECT TIME',
'Category': ['CATEGORY'],
'ConnCount': 633,
'Description': 'Ping scan',
'Source': [
{
'IP4': ['192.168.1.1', '192.168.1.2'],
'Proto': ['icmp']
},
{
'IP4': ['192.168.2.1', '192.168.2.2'],
'Proto': ['icmp']
}
],
'Target': [
{
'Proto': ['icmp'],
'IP4': ['192.168.3.1', '192.168.3.2'],
'Anonymised': True
}
],
'Node': [
{
'SW' : ['KIPPO'],
'Name' : 'NODE_NAME'
}
]
}
>>> jpath_value(msg, 'Format')
'IDEA0'
>>> jpath_value(msg, 'Category')
'CATEGORY'
>>> jpath_value(msg, 'Node.Name')
'NODE_NAME'
>>> jpath_value(msg, 'Source.IP4')
'192.168.1.1'
>>> jpath_values(msg, 'Format')
['IDEA0']
>>> jpath_values(msg, 'Category')
['CATEGORY']
>>> jpath_values(msg, 'Node.Name')
['NODE_NAME']
>>> jpath_values(msg, 'Source.IP4')
['192.168.1.1', '192.168.1.2', '192.168.2.1', '192.168.2.2']
The current implementation has following known drawbacks:
Toplevel element must be a dict-like object
Nested list-like objects are not possible:
[[1,2],[3,4]]
It is not possible to set value to multiple elements at once
It is not possible to customize type of created structure, only lists and dicts are always created
-
exception
pynspect.jpath.
JPathException
(description)[source]¶ Bases:
Exception
Custom JPath specific exception.
This exception will be thrown on module specific errors.
-
pynspect.jpath.
RC_VALUE_DUPLICATE
= 2¶ Status code for
not-unique
, returned by functionjpath_set()
.
-
pynspect.jpath.
RC_VALUE_EXISTS
= 1¶ Status code for
already-exists
, returned by functionjpath_set()
.
-
pynspect.jpath.
RC_VALUE_SET
= 0¶ Status code for
success
, returned by functionjpath_set()
.
-
pynspect.jpath.
RE_JPATH_CHUNK
= re.compile('^([a-zA-Z0-9_]+)(\\[(#|\\*|\\d+)\\])?$')¶ Regular expression for single JPath chunk.
-
pynspect.jpath.
cache_size
()[source]¶ Return the size of internal JPath cache.
- Returns
Cache size
- Return type
int
-
pynspect.jpath.
jpath_exists
(structure, jpath)[source]¶ Check if node at given JPath within given data structure does exist.
- Parameters
structure (str) – data structure to be searched
jpath (str) – JPath to be evaluated
- Returns
True or False
- Return type
bool
-
pynspect.jpath.
jpath_parse
(jpath)[source]¶ Parse given JPath into chunks.
Returns list of dictionaries describing all of the JPath chunks.
- Parameters
jpath (str) – JPath to be parsed into chunks
- Returns
JPath chunks as list of dicts
- Return type
list
- Raises
JPathException – in case of invalid JPath syntax
-
pynspect.jpath.
jpath_parse_c
(jpath)[source]¶ Caching variant of
jpath_parse()
function. Same arguments and return value.For performance reasons thee is no copying and all returned values are references to internal cache. Treat the returned values as read only, or suffer the consequences.
-
pynspect.jpath.
jpath_set
(structure, jpath, value, overwrite=True, unique=False)[source]¶ Set given JPath to given value within given structure.
For performance reasons this method is intentionally not written as recursive.
- Parameters
structure (str) – data structure to be searched
jpath (str) – JPath to be evaluated
value (any) – value of any type to be set at given path
overwrite (bool) – enable/disable overwriting of already existing value
unique (bool) – ensure uniqueness of value, works only for lists
- Returns
numerical return code, one of the (
RC_VALUE_SET
,RC_VALUE_EXISTS
,RC_VALUE_DUPLICATE
)- Return type
int
-
pynspect.jpath.
jpath_unset
(structure, jpath)[source]¶ Unset (delete) value at given JPath within given structure.
For performance reasons this method is intentionally not written as recursive.
- Parameters
structure (str) – data structure to be trimmed
jpath (str) – JPath to be evaluated
-
pynspect.jpath.
jpath_value
(structure, jpath)[source]¶ Return single value or first value from list at given JPath within given data structure.
This method returns None for non-existent JPaths.
- Parameters
structure (str) – data structure to be searched
jpath (str) – JPath to be evaluated
- Returns
None or found value
-
pynspect.jpath.
jpath_values
(structure, jpath)[source]¶ Return all values at given JPath within given data structure.
For performance reasons this method is intentionally not written as recursive.
- Parameters
structure (str) – data structure to be searched
jpath (str) – JPath to be evaluated
- Returns
found values as a list
- Return type
list