-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
178 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,97 @@ | ||
# [JSONPath] for Dart | ||
**Warning!** This is a work-in-progress. Expect the API to change often. Also, feel free to join. | ||
|
||
## Roadmap | ||
- [x] Basic selectors: fields, indices | ||
- [x] Recursive descent (`$..`) | ||
- [x] Wildcard (`$.store.*`) | ||
- [x] Square-bracket field notation (`['foo']`, `$['"some" \'special\' [chars]']`) | ||
- [x] Slice (`articles[1:10:2]`) | ||
- [x] Union (`book[0, 1]`, `book[author, title, price]`) | ||
- [ ] Filtering | ||
```dart | ||
import 'dart:convert'; | ||
import 'package:json_path/json_path.dart'; | ||
[JSONPath]: https://goessner.net/articles/JsonPath/ | ||
void main() { | ||
final json = jsonDecode(''' | ||
{ | ||
"store": { | ||
"book": [ | ||
{ | ||
"category": "reference", | ||
"author": "Nigel Rees", | ||
"title": "Sayings of the Century", | ||
"price": 8.95 | ||
}, | ||
{ | ||
"category": "fiction", | ||
"author": "Evelyn Waugh", | ||
"title": "Sword of Honour", | ||
"price": 12.99 | ||
}, | ||
{ | ||
"category": "fiction", | ||
"author": "Herman Melville", | ||
"title": "Moby Dick", | ||
"isbn": "0-553-21311-3", | ||
"price": 8.99 | ||
}, | ||
{ | ||
"category": "fiction", | ||
"author": "J. R. R. Tolkien", | ||
"title": "The Lord of the Rings", | ||
"isbn": "0-395-19395-8", | ||
"price": 22.99 | ||
} | ||
], | ||
"bicycle": { | ||
"color": "red", | ||
"price": 19.95 | ||
} | ||
} | ||
} | ||
'''); | ||
/// The following code will print: | ||
/// | ||
/// $['store']['book'][0]['price']: 8.95 | ||
/// $['store']['book'][1]['price']: 12.99 | ||
/// $['store']['book'][2]['price']: 8.99 | ||
/// $['store']['book'][3]['price']: 22.99 | ||
/// $['store']['bicycle']['price']: 19.95 | ||
JsonPath(r'$..price') | ||
.filter(json) | ||
.map((result) => '${result.path}:\t${result.value}') | ||
.forEach(print); | ||
} | ||
``` | ||
|
||
## Features and limitations | ||
Generally, this library tries to mimic the [reference implementations], except for the filtering. | ||
Evaluated expressions are not supported, use named filters instead (see below). | ||
### Fields and indices | ||
Both dot-notation (`$.store.book[0].title`) and bracket-notation (`$['store']['book'][2]['title']`) are supported. | ||
|
||
- The dot-notation only recognizes alphanumeric fields starting with a letter. Use bracket-notation for general cases. | ||
- The bracket-notation supports only single quotes. | ||
|
||
### Wildcards | ||
Wildcards (`*`) can be used for objects (`$.store.*`) and arrays (`$.store.book[*]`); | ||
|
||
### Recursion | ||
Use `..` to iterate all elements recursively. E.g. `$.store..price` matches all prices in the store. | ||
|
||
### Array slice | ||
Use `[start:end:step]` to filter arrays. Any index can be omitted E.g. `$.store.book[3::2]` selects all even books | ||
starting from the 4th. Negative `start` and `end` are also supported. | ||
|
||
### Unions | ||
Array (`book[0,1]`) and object (`book[author,title,price]`) unions are supported. | ||
Object unions support the bracket-notation. | ||
|
||
### Filtering | ||
Due to the nature of Dart language, filtering expressions like `$..book[?(@.price<10)]` are NOT supported. | ||
Instead, use the callback-kind of filters. | ||
```dart | ||
/// Select all elements with price under 20 | ||
JsonPath(r'$.store..[?discounted]', filter: { | ||
'discounted': (e) => e is Map && e['price'] is num && e['price'] < 20 | ||
}); | ||
``` | ||
|
||
[JSONPath]: https://goessner.net/articles/JsonPath/ | ||
[reference implementations]: https://goessner.net/articles/JsonPath/index.html#e4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
typedef Predicate = bool Function(dynamic element); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import 'package:json_path/json_path.dart'; | ||
import 'package:json_path/src/predicate.dart'; | ||
import 'package:json_path/src/result.dart'; | ||
import 'package:json_path/src/selector/selector.dart'; | ||
import 'package:json_path/src/selector/selector_mixin.dart'; | ||
|
||
class Filter with SelectorMixin { | ||
Filter(this.name, this.predicate); | ||
|
||
final String name; | ||
|
||
final Predicate predicate; | ||
|
||
@override | ||
Iterable<Result> filter(Iterable<Result> results) => | ||
results.where((r) => predicate(r.value)); | ||
|
||
@override | ||
String expression([Selector previous]) => '[?$name]'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters