json_path_plus
A Dart port of JSONPath-Plus — a full-featured JSONPath query engine with filter expressions, type operators, array slices, and safe expression evaluation.
Features
- Basic path syntax: dot notation, bracket notation, wildcards, recursive descent (
..) - Filter expressions:
[?(@.price > 10)]with@property,@parent,@root,@path - Type operators:
@string(),@number(),@boolean(),@integer(),@null(),@array(),@object(),@scalar(),@other() ~property-name operator: returns the key name instead of value^parent selector: returns the parent of the matched node- Array slices: Python-style
[start:end:step] - Dynamic properties:
[(1+2)]evaluates to index 3 - Comma-separated keys:
[0,1]selects multiple indices - Backtick-escaped properties:
`0`for literal property lookup - Multiple result types:
value,path,pointer,parent,parentProperty,all - Safe expression evaluator: No
dart:mirrors, noeval(), no external dependencies
Getting started
Install
Add to your pubspec.yaml:
dependencies:
json_path_plus: ^1.0.0
Then run:
dart pub get
Requirements
- Dart SDK 3.0+ (sound null safety)
- Zero external runtime dependencies
- Flutter-compatible (no
dart:mirrors)
Usage
Basic queries
import 'package:json_path_plus/json_path_plus.dart';
final data = {
'store': {
'book': [
{'title': 'Sayings of the Century', 'price': 8.95},
{'title': 'Moby Dick', 'price': 12.99},
{'title': 'The Lord of the Rings', 'price': 22.99},
],
},
};
// Simple query — returns all titles
final titles = JSONPath.query(r'$.store.book[*].title', data);
print(titles); // ['Sayings of the Century', 'Moby Dick', 'The Lord of the Rings']
// Filter: books over $10
final expensive = JSONPath.query(r'$.store.book[?(@.price > 10)].title', data);
print(expensive); // ['Moby Dick', 'The Lord of the Rings']
// With full options — get paths instead of values
final result = JSONPath.evaluate(JsonPathOptions(
path: r'$..book[?(@.price > 10)]',
json: data,
resultType: 'path',
));
print(result); // ["$['store']['book'][1]", "$['store']['book'][2]"]
Walgreens-style @property filter
Match keys dynamically using @property in filter expressions:
final data = {
'productInfo': {
'filmStripUrl': [
{'stripUrl1': '...', 'zoomImageUrl1': '//pics.example.com/image1.jpg'},
{'stripUrl2': '...', 'zoomImageUrl2': '//pics.example.com/image2.jpg'},
],
},
};
final zoomUrls = JSONPath.evaluate(JsonPathOptions(
path: r'$.productInfo.filmStripUrl[*][?(@property.indexOf("zoomImageUrl") === 0)]',
json: data,
));
print(zoomUrls); // ['//pics.example.com/image1.jpg', '//pics.example.com/image2.jpg']
Array slice
final sliced = JSONPath.query(r'$[1:4:2]', [0, 1, 2, 3, 4, 5]);
print(sliced); // [1, 3]
Type operator filter
final strings = JSONPath.query(
r'$[?(@string())]',
['hello', 42, true, null, 'world'],
);
print(strings); // ['hello', 'world']
API
JSONPath.evaluate(options)
The main evaluation entry point. Accepts either a JsonPathOptions object or positional arguments.
static dynamic evaluate(
Object? pathOrOpts, [
Object? json,
void Function(Object?, String, JsonPathMatch)? callback,
Object? Function(Object?, List<String>, Object?, String?)? otherTypeCallback,
])
JSONPath.query(path, json, {wrap})
Shorthand for value-only queries. Always returns List<Object?>.
static List<Object?> query(String path, Object json, {bool wrap = true})
JSONPath.toPathArray(expr) / toPathString(path) / toPointer(path)
Convert between path representations:
JSONPath.toPathArray(r"$['store']['book'][0]['title']");
// → ['$', 'store', 'book', '0', 'title']
JSONPath.toPathString(['$', 'store', 'book', '0', 'title']);
// → "$['store']['book'][0]['title']"
JSONPath.toPointer(['$', 'store', 'book', '0', 'title']);
// → '/store/book/0/title'
JsonPathOptions
| Field | Type | Default | Description |
|---|---|---|---|
path |
String |
required | JSONPath expression |
json |
Object |
required | JSON data |
resultType |
String |
'value' |
'value', 'path', 'pointer', 'parent', 'parentProperty', 'all' |
flatten |
bool |
false |
Flatten nested arrays |
wrap |
bool |
true |
Always return array |
sandbox |
Map? |
{} |
Variables for filter expressions |
eval |
Object? |
'safe' |
'safe', 'native', false |
ignoreEvalErrors |
bool |
false |
Silently ignore eval errors |
callback |
Function? |
null |
Per-match callback |
otherTypeCallback |
Function? |
throws | For @other() type |
JsonPathMatch
class JsonPathMatch {
final Object? value; // The matched value
final String path; // The path string
final List<String>? paths; // Path components
final Object? parent; // Parent object
final String? property; // Property name
Object? pointer; // JSON Pointer
}
SafeEval
The safe expression evaluator for filter conditions. Supports arithmetic, comparison,
logical operators, and string concatenation — without dart:mirrors or eval().
final result = SafeEval.evaluate('1 + 2 * 3 > 5 && "hello" + " world"');
// → true
Constraints
- Zero external runtime dependencies (only
dart:core,dart:math,dart:convert) - Sound null safety (Dart 3.x, SDK
>=3.0.0 <4.0.0) - No
dart:mirrors(Flutter-compatible) - No
eval()orFunction.apply()— uses a custom expression parser
Similar packages
json_path— Another JSONPath implementation for Dart with a different feature setjson_path_plus— This package, a Dart port of JSONPath-Plus with extended operatorsjson5_plus— JSON5 parser (by the same team)zikzak_json— Best-effort JSON parser with simdjson fallback (by the same team)
Powered by ZikZak AI
json_path_plus is developed by ZikZak AI to serve as the JSONPath query engine for high-throughput data extraction workloads.
- 🌐 zuzu.dev
- 🐙 GitHub
- 🐛 Issue Tracker
Sponsors
Thanks to ZikZak AI for sponsoring this project!
ZikZak AI is an AI-Powered Price Comparison app that you scan barcodes, and discover amazing savings instantly. Your personal shopping assistant that never sleeps.
Licensed under the MIT License.
Libraries
- json_path_plus
- A Dart port of JSONPath-Plus — full-featured JSONPath query engine.


