README.md
1# jsonpath_lib
2
3[![Build Status](https://travis-ci.org/freestrings/jsonpath.svg?branch=master)](https://travis-ci.org/freestrings/jsonpath)
4![crates.io](https://img.shields.io/crates/v/jsonpath_lib.svg)
5![npm](https://img.shields.io/npm/v/jsonpath-wasm.svg?label=npm%20%60jsonpath-wasm%60)
6![Codecov](https://img.shields.io/codecov/c/github/freestrings/jsonpath.svg?token=92c41b4e7cf04a9cbebc08f68c5da615)
7
8`Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현으로 `Webassembly`와 `Javascript`에서도 유사한 API 인터페이스를 제공 한다.
9
10It is JsonPath [JsonPath](https://goessner.net/articles/JsonPath/) engine written in `Rust`. it provide a similar API interface in `Webassembly` and` Javascript` too.
11
12- [Webassembly Demo](https://freestrings.github.io/jsonpath/)
13- [NPM jsonpath-wasm - webassembly](https://www.npmjs.com/package/jsonpath-wasm)
14
15## Rust API
16
17<details><summary><b>jsonpath_lib crate</b></summary>
18
19Go to [`jsonpath_lib` creates.io](https://crates.io/crates/jsonpath_lib)
20
21```rust
22extern crate jsonpath_lib as jsonpath;
23```
24
25</details>
26
27<details><summary><b>Rust - jsonpath::Selector struct</b></summary>
28
29```rust
30#[derive(Deserialize, PartialEq, Debug)]
31struct Friend {
32 name: String,
33 age: Option<u8>,
34}
35
36let json_obj = json!({
37 "school": {
38 "friends": [
39 {"name": "친구1", "age": 20},
40 {"name": "친구2", "age": 20}
41 ]
42 },
43 "friends": [
44 {"name": "친구3", "age": 30},
45 {"name": "친구4"}
46]});
47
48let mut selector = Selector::new();
49
50let result = selector
51 .path("$..[?(@.age >= 30)]").unwrap()
52 .value(&json_obj)
53 .select().unwrap();
54
55assert_eq!(vec![&json!({"name": "친구3", "age": 30})], result);
56
57let result = selector.select_as_str().unwrap();
58assert_eq!(r#"[{"name":"친구3","age":30}]"#, result);
59
60let result = selector.select_as::<Friend>().unwrap();
61assert_eq!(vec![Friend { name: "친구3".to_string(), age: Some(30) }], result);
62```
63
64</details>
65
66<details><summary><b>Rust - jsonpath::SelectorMut struct</b></summary>
67
68```rust
69let json_obj = json!({
70 "school": {
71 "friends": [
72 {"name": "친구1", "age": 20},
73 {"name": "친구2", "age": 20}
74 ]
75 },
76 "friends": [
77 {"name": "친구3", "age": 30},
78 {"name": "친구4"}
79]});
80
81let mut selector_mut = SelectorMut::new();
82
83let result = selector_mut
84 .str_path("$..[?(@.age == 20)].age").unwrap()
85 .value(json_obj)
86 .replace_with(&mut |v| {
87 let age = if let Value::Number(n) = v {
88 n.as_u64().unwrap() * 2
89 } else {
90 0
91 };
92
93 Some(json!(age))
94 }).unwrap()
95 .take().unwrap();
96
97assert_eq!(result, json!({
98 "school": {
99 "friends": [
100 {"name": "친구1", "age": 40},
101 {"name": "친구2", "age": 40}
102 ]
103 },
104 "friends": [
105 {"name": "친구3", "age": 30},
106 {"name": "친구4"}
107]}));
108```
109
110</details>
111
112<details><summary><b>Rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)</b></summary>
113
114```rust
115let json_obj = json!({
116 "school": {
117 "friends": [
118 {"name": "친구1", "age": 20},
119 {"name": "친구2", "age": 20}
120 ]
121 },
122 "friends": [
123 {"name": "친구3", "age": 30},
124 {"name": "친구4"}
125]});
126
127let json = jsonpath::select(&json_obj, "$..friends[0]").unwrap();
128
129assert_eq!(json, vec![
130 &json!({"name": "친구3", "age": 30}),
131 &json!({"name": "친구1", "age": 20})
132]);
133```
134
135</details>
136
137
138<details><summary><b>Rust - jsonpath::select_as_str(json_str: &str, jsonpath: &str)</b></summary>
139
140```rust
141let ret = jsonpath::select_as_str(r#"
142{
143 "school": {
144 "friends": [
145 {"name": "친구1", "age": 20},
146 {"name": "친구2", "age": 20}
147 ]
148 },
149 "friends": [
150 {"name": "친구3", "age": 30},
151 {"name": "친구4"}
152 ]
153}
154"#, "$..friends[0]").unwrap();
155
156assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#);
157```
158
159</details>
160
161<details><summary><b>Rust - jsonpath::select_as<T: `serde::de::DeserializeOwned`>(json_str: &str, jsonpath: &str)</b></summary>
162
163```rust
164#[derive(Deserialize, PartialEq, Debug)]
165struct Person {
166 name: String,
167 age: u8,
168 phones: Vec<String>,
169}
170
171let ret: Vec<Person> = jsonpath::select_as(r#"
172{
173 "person":
174 {
175 "name": "Doe John",
176 "age": 44,
177 "phones": [
178 "+44 1234567",
179 "+44 2345678"
180 ]
181 }
182}
183"#, "$.person").unwrap();
184
185let person = Person {
186 name: "Doe John".to_string(),
187 age: 44,
188 phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()],
189};
190
191assert_eq!(ret[0], person);
192```
193
194</details>
195
196<details><summary><b>Rust - jsonpath::Compiled::compile(jsonpath: &str)</b></summary>
197
198```rust
199let template = jsonpath::Compiled::compile("$..friends[0]").unwrap();
200
201let json_obj = json!({
202 "school": {
203 "friends": [
204 {"name": "친구1", "age": 20},
205 {"name": "친구2", "age": 20}
206 ]
207 },
208 "friends": [
209 {"name": "친구3", "age": 30},
210 {"name": "친구4"}
211]});
212
213let json = template.select(&json_obj).unwrap();
214
215assert_eq!(json, vec![
216 &json!({"name": "친구3", "age": 30}),
217 &json!({"name": "친구1", "age": 20})
218]);
219```
220
221</details>
222
223<details><summary><b>Rust - jsonpath::selector(json: &serde_json::value::Value)</b></summary>
224
225```rust
226let json_obj = json!({
227 "school": {
228 "friends": [
229 {"name": "친구1", "age": 20},
230 {"name": "친구2", "age": 20}
231 ]
232 },
233 "friends": [
234 {"name": "친구3", "age": 30},
235 {"name": "친구4"}
236]});
237
238let mut selector = jsonpath::selector(&json_obj);
239
240let json = selector("$..friends[0]").unwrap();
241
242assert_eq!(json, vec![
243 &json!({"name": "친구3", "age": 30}),
244 &json!({"name": "친구1", "age": 20})
245]);
246
247let json = selector("$..friends[1]").unwrap();
248
249assert_eq!(json, vec![
250 &json!({"name": "친구4"}),
251 &json!({"name": "친구2", "age": 20})
252]);
253```
254
255</details>
256
257<details><summary><b>Rust - jsonpath::selector_as<T: serde::de::DeserializeOwned>(json: &serde_json::value::Value)</b></summary>
258
259```rust
260let json_obj = json!({
261 "school": {
262 "friends": [
263 {"name": "친구1", "age": 20},
264 {"name": "친구2", "age": 20}
265 ]
266 },
267 "friends": [
268 {"name": "친구3", "age": 30},
269 {"name": "친구4"}
270]});
271
272#[derive(Deserialize, PartialEq, Debug)]
273struct Friend {
274 name: String,
275 age: Option<u8>,
276}
277
278let mut selector = jsonpath::selector_as::<Friend>(&json_obj);
279
280let json = selector("$..friends[0]").unwrap();
281
282let ret = vec!(
283 Friend { name: "친구3".to_string(), age: Some(30) },
284 Friend { name: "친구1".to_string(), age: Some(20) }
285);
286assert_eq!(json, ret);
287
288let json = selector("$..friends[1]").unwrap();
289
290let ret = vec!(
291 Friend { name: "친구4".to_string(), age: None },
292 Friend { name: "친구2".to_string(), age: Some(20) }
293);
294
295assert_eq!(json, ret);
296```
297
298</details>
299
300<details><summary><b>Rust - jsonpath::delete(value: &Value, path: &str)</b></summary>
301
302```rust
303let json_obj = json!({
304 "school": {
305 "friends": [
306 {"name": "친구1", "age": 20},
307 {"name": "친구2", "age": 20}
308 ]
309 },
310 "friends": [
311 {"name": "친구3", "age": 30},
312 {"name": "친구4"}
313]});
314
315let ret = jsonpath::delete(json_obj, "$..[?(20 == @.age)]").unwrap();
316
317assert_eq!(ret, json!({
318 "school": {
319 "friends": [
320 null,
321 null
322 ]
323 },
324 "friends": [
325 {"name": "친구3", "age": 30},
326 {"name": "친구4"}
327]}));
328```
329
330</details>
331
332<details><summary><b>Rust - jsonpath::replace_with<F: FnMut(&Value) -> Value>(value: &Value, path: &str, fun: &mut F)</b></summary>
333
334```rust
335let json_obj = json!({
336 "school": {
337 "friends": [
338 {"name": "친구1", "age": 20},
339 {"name": "친구2", "age": 20}
340 ]
341 },
342 "friends": [
343 {"name": "친구3", "age": 30},
344 {"name": "친구4"}
345]});
346
347let ret = jsonpath::replace_with(json_obj, "$..[?(@.age == 20)].age", &mut |v| {
348 let age = if let Value::Number(n) = v {
349 n.as_u64().unwrap() * 2
350 } else {
351 0
352 };
353
354 Some(json!(age))
355}).unwrap();
356
357assert_eq!(ret, json!({
358 "school": {
359 "friends": [
360 {"name": "친구1", "age": 40},
361 {"name": "친구2", "age": 40}
362 ]
363 },
364 "friends": [
365 {"name": "친구3", "age": 30},
366 {"name": "친구4"}
367]}));
368```
369
370</details>
371
372[Rust - Other Examples](https://github.com/freestrings/jsonpath/wiki/rust-examples)
373
374## Javascript API
375
376<details><summary><b>npm package</b></summary>
377
378##### jsonpath-wasm
379
380Goto [`jsonpath-wasm` npmjs.org](https://www.npmjs.com/package/jsonpath-wasm)
381
382```javascript
383// browser
384import * as jsonpath from "jsonpath-wasm";
385// NodeJs
386const jsonpath = require('jsonpath-wasm');
387```
388
389##### jsonpath-wasm
390`wasm-bindgen` 리턴 타입 제약 때문에 빌더 패턴은 지원하지 않는다.
391
392It does not support `builder-pattern` due to the `return type` restriction of `wasm-bindgen`.
393
394```javascript
395let jsonObj = {
396 "school": {
397 "friends": [
398 {"name": "친구1", "age": 20},
399 {"name": "친구2", "age": 20}
400 ]
401 },
402 "friends": [
403 {"name": "친구3", "age": 30},
404 {"name": "친구4"}
405 ]
406};
407
408let ret = [
409 {"name": "친구3", "age": 30},
410 {"name": "친구1", "age": 20}
411];
412
413let selector = new jsonpath.Selector();
414selector.path('$..friends[0]');
415selector.value(jsonObj);
416
417let retObj = selector.select();
418
419console.log(JSON.stringify(ret) == JSON.stringify(retObj));
420
421// => true
422```
423
424빌더 패턴 제약은 `Selector class`와 동일하다.
425
426```javascript
427let jsonObj = {
428 'school': {
429 'friends': [
430 {'name': '친구1', 'age': 20},
431 {'name': '친구2', 'age': 20},
432 ],
433 },
434 'friends': [
435 {'name': '친구3', 'age': 30},
436 {'name': '친구4'},
437 ],
438};
439
440let selector = new jsonpath.SelectorMut();
441selector.path('$..[?(@.age == 20)]');
442
443{
444 selector.value(jsonObj);
445 selector.deleteValue();
446
447 let resultObj = {
448 'school': {'friends': [null, null]},
449 'friends': [
450 {'name': '친구3', 'age': 30},
451 {'name': '친구4'},
452 ],
453 };
454 console.log(JSON.stringify(selector.take()) !== JSON.stringify(resultObj));
455
456 // => true
457}
458
459{
460 selector.value(jsonObj);
461 selector.replaceWith((v) => {
462 v.age = v.age * 2;
463 return v;
464 });
465
466 let resultObj = {
467 'school': {
468 'friends': [
469 {'name': '친구1', 'age': 40},
470 {'name': '친구2', 'age': 40},
471 ],
472 },
473 'friends': [
474 {'name': '친구3', 'age': 30},
475 {'name': '친구4'},
476 ],
477 };
478 console.log(JSON.stringify(selector.take()) !== JSON.stringify(resultObj));
479
480 // => true
481}
482```
483
484</details>
485
486<details><summary><b>Javascript - jsonpath.select(json: string|object, jsonpath: string)</b></summary>
487
488```javascript
489let jsonObj = {
490 "school": {
491 "friends": [
492 {"name": "친구1", "age": 20},
493 {"name": "친구2", "age": 20}
494 ]
495 },
496 "friends": [
497 {"name": "친구3", "age": 30},
498 {"name": "친구4"}
499 ]
500};
501
502let ret = [
503 {"name": "친구3", "age": 30},
504 {"name": "친구1", "age": 20}
505];
506
507
508let selectAsString = jsonpath.select(JSON.stringify(jsonObj), '$..friends[0]');
509let selectAsObj = jsonpath.select(jsonObj, '$..friends[0]');
510
511console.log(
512 JSON.stringify(ret) == JSON.stringify(selectAsString),
513 JSON.stringify(ret) == JSON.stringify(selectAsObj)
514);
515
516// => true, true
517```
518
519</details>
520
521<details><summary><b>Javascript - jsonpath.compile(jsonpath: string)</b></summary>
522
523```javascript
524let error = jsonpath.compile('');
525console.log(typeof error, error); //string 'path error'
526
527let template = jsonpath.compile('$..friends[0]');
528
529let jsonObj = {
530 "school": {
531 "friends": [
532 {"name": "친구1", "age": 20},
533 {"name": "친구2", "age": 20}
534 ]
535 },
536 "friends": [
537 {"name": "친구3", "age": 30},
538 {"name": "친구4"}
539 ]
540};
541
542let ret = [
543 {"name": "친구3", "age": 30},
544 {"name": "친구1", "age": 20}
545];
546
547let selectAsString = template(JSON.stringify(jsonObj));
548let selectAsObj = template(jsonObj);
549
550console.log(
551 JSON.stringify(ret) == JSON.stringify(selectAsString),
552 JSON.stringify(ret) == JSON.stringify(selectAsObj)
553);
554
555// => true, true
556
557let jsonObj2 = {
558 "school": {
559 "friends": [
560 {"name": "Millicent Norman"},
561 {"name": "Vincent Cannon"}
562 ]
563 },
564 "friends": [ {"age": 30}, {"age": 40} ]
565};
566
567let ret2 = [
568 {"age": 30},
569 {"name": "Millicent Norman"}
570];
571
572let selectAsString2 = template(JSON.stringify(jsonObj2));
573let selectAsObj2 = template(jsonObj2);
574
575console.log(
576 JSON.stringify(ret2) == JSON.stringify(selectAsString2),
577 JSON.stringify(ret2) == JSON.stringify(selectAsObj2)
578);
579
580// => true, true
581```
582
583</details>
584
585<details><summary><b>Javascript - jsonpath.selector(json: string|object)</b></summary>
586
587```javascript
588let jsonObj = {
589 "school": {
590 "friends": [
591 {"name": "친구1", "age": 20},
592 {"name": "친구2", "age": 20}
593 ]
594 },
595 "friends": [
596 {"name": "친구3", "age": 30},
597 {"name": "친구4"}
598 ]
599};
600
601let ret1 = [
602 {"name": "친구3", "age": 30},
603 {"name": "친구1", "age": 20}
604];
605
606let ret2 = [
607 {"name": "친구4"},
608 {"name": "친구2", "age": 20}
609];
610
611let selector = jsonpath.selector(jsonObj);
612// or as json string
613// let selector = jsonpath.selector(JSON.stringify(jsonObj));
614
615let select1 = selector('$..friends[0]');
616let select2 = selector('$..friends[1]');
617
618console.log(
619 JSON.stringify(ret1) == JSON.stringify(select1),
620 JSON.stringify(ret2) == JSON.stringify(select2)
621);
622
623// => true, true
624```
625
626</details>
627
628<details><summary><b>Javascript - jsonpath.deleteValue(json: string|object, path: string)</b></summary>
629
630```javascript
631let jsonObj = {
632 "school": {
633 "friends": [
634 {"name": "친구1", "age": 20},
635 {"name": "친구2", "age": 20}
636 ]
637 },
638 "friends": [
639 {"name": "친구3", "age": 30},
640 {"name": "친구4"}
641 ]
642};
643
644let _1 = jsonpath.deleteValue(jsonObj, '$..friends[0]');
645let result = jsonpath.deleteValue(_1, '$..friends[1]');
646
647console.log(JSON.stringify(result) !== JSON.stringify({
648 "school": { "friends": [null, null]},
649 "friends": [null, null]
650}));
651
652// => true
653
654```
655
656</details>
657
658<details><summary><b>Javascript - jsonpath.replaceWith(json: string|object, path: string, fun: function(json: object) => json: object</b></summary>
659
660```javascript
661let jsonObj = {
662 "school": {
663 "friends": [
664 {"name": "친구1", "age": 20},
665 {"name": "친구2", "age": 20}
666 ]
667 },
668 "friends": [
669 {"name": "친구3", "age": 30},
670 {"name": "친구4"}
671 ]
672};
673
674let result = jsonpath.replaceWith(jsonObj, '$..friends[0]', (v) => {
675 v.age = v.age * 2;
676 return v;
677});
678
679console.log(JSON.stringify(result) === JSON.stringify({
680 "school": {
681 "friends": [
682 {"name": "친구1", "age": 40},
683 {"name": "친구2", "age": 20}
684 ]
685 },
686 "friends": [
687 {"name": "친구3", "age": 60},
688 {"name": "친구4"}
689 ]
690}));
691
692// => true
693
694```
695
696</details>
697
698[Javascript - Other Examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples)