@zakjan/objectpath
v1.0.3
Published
Expression language for querying JSON objects using ANTLR4
Downloads
1
Readme
ObjectPath
Expression language for querying JSON objects using ANTLR4. It can be easily ported into any target language supported as ANTLR4 runtime. Test usecases are shared to ensure consistent results. Currently implemented in TypeScript, Java.
Usage
JavaScript
Install
npm install @zakjan/objectpath
Use
import { getByPath } from '@zakjan/objectpath';
const data = { items: [{ type: "X", name: "Ben" }] };
const path = "items.find(type == 'X').name";
const result = getByPath(data, path); // -> Ben
Java
Install
Add to pom.xml
:
<dependency>
<groupId>cz.zakjan</groupId>
<artifactId>objectpath</artifactId>
<version>x.y.z</version>
</dependency>
Use
import static cz.zakjan.objectpath.GetByPath.getByPath;
Object data = new HashMap<String, Object>() {{
put("items", new ArrayList<Object>() {{
add(new HashMap<String, Object>() {{
put("type", "X");
put("type", "Ben");
}});
}});
}};
String path = "items.find(type == 'X').name";
Object result = getByPath(data, path); // -> Ben
Syntax
The basic syntax is compatible with lodash.get. A simple syntax for simple cases, yet supporting more complex cases.
Supported features (by priority):
- access expressions
- root object reference
$
- current object reference
@
- default, can be omitted - dot access
object.field
- bracket access
array[0]
array[-1]
object['a field']
- array find
array.find(field == 'X')
array.find($.rootField == 'X')
- array filter
array.filter(field == 'X')
array.filter($.rootField == 'X')
array.filter(field == 'X' && array.filter(field == 'Y'))
- array map
array.map(field)
array.map(@ * 2)
- root object reference
- functions
toString
toNumber
join
split
sum
dateTimestampToIsoString
- returns date ISO stringYYYY-MM-DD'T'HH:mm:ss.SSSX
dateIsoStringToTimestamp
- accepts any valid date ISO string
- operators
- unary
+
-
- unary logical NOT
!
- multiplicative
*
/
- additive
+
-
- equality
==
!=
- relational
<
>
<=
>=
- logical AND
&&
- logical OR
||
- conditional
?:
- unary
- primitives - string, number, boolean,
null
See detailed examples in test directory.
Strict equality
Equality operator ==
uses strict equality, ===
in JS, Object.equals
in Java.
Strict boolean truth table
false
, null
evaluates to false
, everything else evaluates to true
. This differs from JS, which evaluates 0
, ''
also to false
.
Logical operators on non-boolean operands
In case of logical operator applied to non-boolean operands, left operand is coerced to boolean for condition check, and the original value of left or right operand is returned. For example falseField || field
returns field
.
Note that nullish coalescing operator ??
is different from logical OR ||
, it applies only if left side evaluates to null
.
Optional chaining
Some programming languages have optional chaining operator ?.
. This is the default and only mode of operation of this library by design.
Null vs. undefined
In case of non-existing property, null
is returned. This is because undefined
is a JS-only construct, it even can't be stored in JSON.
Parsing errors
In case of parsing errors, function getByPath
silently catches the error and returns null
. If you wish to handle the error on your own, call parsePath
and getByParsedPath
separately.
Why yet another library?
Other libraries are either missing more advanced extracting features or don't have consistent implementation across multiple languages.
JSONPath
- (blocker) doesn't use array filter result as context for further traversing, see https://github.com/json-path/JsonPath/issues/272
- (blocker) language-specific implementations are completely separate, they differ slightly in edge cases and path preprocessing is needed to make it behave consistently
- requires root object reference
$
in begining
XPath
- language-specific implementations are completely separate
- too different from JS syntax
SpEL
- language-specific implementations are completely separate
jq
- only C implementation
lodash.get, JSONata, JSPath, dot-prop, ...
- missing more advanced features
TODO
- float/double primitives and operations
- long operations
- array slicing
array[start:end:step]
- computed member access
object[path]
- short circuiting - don't evaluate right side of operators if left side is enough
- complete operator precedence table - JavaScript, Java
- enable adding custom functions
- explore if also AST visitor can be generated from an universal language