文件最后提交记录最后更新时间
1 个月前
2 个月前
2 个月前
2 个月前
2 个月前
2 天前
3 个月前
2 个月前
3 天前
3 天前
3 个月前
2 天前
3 个月前
3 天前
3 个月前
3 个月前
3 个月前
3 个月前
3 个月前
README

jsonpath_lib

Build Status crates.io npm Codecov

Rust 버전 JsonPath 구현으로 Webassembly와 Javascript에서도 유사한 API 인터페이스를 제공 한다.

It is JsonPath JsonPath engine written in Rust. it provide a similar API interface in Webassembly andJavascript too.

Place in the monorepo

This is a first-party crate in the start-technologies monorepo. It originated as a fork of freestrings/jsonpath and has since fully diverged — it is maintained here as first-party code, with no intent to sync back upstream.

  • Path: shared-libs/crates/jsonpath
  • Package name: jsonpath_lib (differs from the directory name jsonpath; build/test with cargo … -p jsonpath_lib).
  • Crate type: rlib + cdylib (the cdylib backs the wasm/ bindings).
  • Consumers: start-core uses jsonpath_lib::Compiled in src/config/hook.rs.
  • Dependencies: the sibling imbl-value crate (supplies the Value/Vector types this engine queries), plus serde / serde_json and log. It is a direct path dependency — no [patch], no crates.io pull.

Rust API

jsonpath_lib crate

Use the in-tree jsonpath_lib path dependency; the upstream crates.io release is a different implementation.

extern crate jsonpath_lib as jsonpath;
Rust - jsonpath::Selector struct
#[derive(Deserialize, PartialEq, Debug)]
struct Friend {
    name: String,
    age: Option<u8>,
}

let json_obj = json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]});

let mut selector = Selector::new();

let result = selector
    .path("$..[?(@.age >= 30)]").unwrap()
    .value(&json_obj)
    .select().unwrap();

assert_eq!(vector![&json!({"name": "친구3", "age": 30})], result);

let result = selector.select_as_str().unwrap();
assert_eq!(r#"[{"name":"친구3","age":30}]"#, result);

let result = selector.select_as::<Friend>().unwrap();
assert_eq!(vector![Friend { name: "친구3".to_string(), age: Some(30) }], result);
Rust - jsonpath::SelectorMut struct
let json_obj = json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]});

let mut selector_mut = SelectorMut::new();

let result = selector_mut
    .str_path("$..[?(@.age == 20)].age").unwrap()
    .value(json_obj)
    .replace_with(&mut |v| {
        let age = if let Value::Number(n) = v {
            n.as_u64().unwrap() * 2
        } else {
            0
        };

        Some(json!(age))
    }).unwrap()
    .take().unwrap();

assert_eq!(result, json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 40},
            {"name": "친구2", "age": 40}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]}));
Rust - jsonpath::select(json: &imbl_value::value::Value, jsonpath: &str)
let json_obj = json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]});

let json = jsonpath::select(&json_obj, "$..friends[0]").unwrap();

assert_eq!(json, vector![
    &json!({"name": "친구3", "age": 30}),
    &json!({"name": "친구1", "age": 20})
]);
Rust - jsonpath::select_as_str(json_str: &str, jsonpath: &str)
let ret = jsonpath::select_as_str(r#"
{
    "school": {
        "friends": [
                {"name": "친구1", "age": 20},
                {"name": "친구2", "age": 20}
            ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
    ]
}
"#, "$..friends[0]").unwrap();

assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#);
Rust - jsonpath::select_as<T: `serde::de::DeserializeOwned`>(json_str: &str, jsonpath: &str)
#[derive(Deserialize, PartialEq, Debug)]
struct Person {
    name: String,
    age: u8,
    phones: Vector<String>,
}

let ret: Vector<Person> = jsonpath::select_as(r#"
{
    "person":
        {
            "name": "Doe John",
            "age": 44,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }
}
"#, "$.person").unwrap();

let person = Person {
    name: "Doe John".to_string(),
    age: 44,
    phones: vector!["+44 1234567".to_string(), "+44 2345678".to_string()],
};

assert_eq!(ret[0], person);
Rust - jsonpath::PathCompiled::compile(jsonpath: &str)
let template = jsonpath::PathCompiled::compile("$..friends[0]").unwrap();

let json_obj = json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]});

let json = template.select(&json_obj).unwrap();

assert_eq!(json, vector![
    &json!({"name": "친구3", "age": 30}),
    &json!({"name": "친구1", "age": 20})
]);
Rust - jsonpath::selector(json: &imbl_value::value::Value)
let json_obj = json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]});

let mut selector = jsonpath::selector(&json_obj);

let json = selector("$..friends[0]").unwrap();

assert_eq!(json, vector![
    &json!({"name": "친구3", "age": 30}),
    &json!({"name": "친구1", "age": 20})
]);

let json = selector("$..friends[1]").unwrap();

assert_eq!(json, vector![
    &json!({"name": "친구4"}),
    &json!({"name": "친구2", "age": 20})
]);
Rust - jsonpath::selector_as<T: serde::de::DeserializeOwned>(json: &imbl_value::value::Value)
let json_obj = json!({
    "school": {
       "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]});

#[derive(Deserialize, PartialEq, Debug)]
struct Friend {
    name: String,
    age: Option<u8>,
}

let mut selector = jsonpath::selector_as::<Friend>(&json_obj);

let json = selector("$..friends[0]").unwrap();

let ret = vector!(
    Friend { name: "친구3".to_string(), age: Some(30) },
    Friend { name: "친구1".to_string(), age: Some(20) }
);
assert_eq!(json, ret);

let json = selector("$..friends[1]").unwrap();

let ret = vector!(
    Friend { name: "친구4".to_string(), age: None },
    Friend { name: "친구2".to_string(), age: Some(20) }
);

assert_eq!(json, ret);
Rust - jsonpath::delete(value: &Value, path: &str)
let json_obj = json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]});

let ret = jsonpath::delete(json_obj, "$..[?(20 == @.age)]").unwrap();

assert_eq!(ret, json!({
    "school": {
        "friends": [
            null,
            null
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]}));
Rust - jsonpath::replace_with<F: FnMut(&Value) -> Value>(value: &Value, path: &str, fun: &mut F)
let json_obj = json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 20},
            {"name": "친구2", "age": 20}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]});

let ret = jsonpath::replace_with(json_obj, "$..[?(@.age == 20)].age", &mut |v| {
    let age = if let Value::Number(n) = v {
        n.as_u64().unwrap() * 2
    } else {
        0
    };

    Some(json!(age))
}).unwrap();

assert_eq!(ret, json!({
    "school": {
        "friends": [
            {"name": "친구1", "age": 40},
            {"name": "친구2", "age": 40}
        ]
    },
    "friends": [
        {"name": "친구3", "age": 30},
        {"name": "친구4"}
]}));

Rust - Other Examples

Historical upstream JavaScript API

The examples below describe the upstream jsonpath-wasm npm package, not a Start9-published artifact. Monorepo consumers use the Rust crate.

npm package
jsonpath-wasm

Goto jsonpath-wasm npmjs.org

// browser
import * as jsonpath from 'jsonpath-wasm'
// NodeJs
const jsonpath = require('jsonpath-wasm')
jsonpath-wasm

wasm-bindgen 리턴 타입 제약 때문에 빌더 패턴은 지원하지 않는다.

It does not support builder-pattern due to the return type restriction of wasm-bindgen.

let jsonObj = {
  school: {
    friends: [
      { name: '친구1', age: 20 },
      { name: '친구2', age: 20 },
    ],
  },
  friends: [{ name: '친구3', age: 30 }, { name: '친구4' }],
}

let ret = [
  { name: '친구3', age: 30 },
  { name: '친구1', age: 20 },
]

let selector = new jsonpath.Selector()
selector.path('$..friends[0]')
selector.value(jsonObj)

let retObj = selector.select()

console.log(JSON.stringify(ret) == JSON.stringify(retObj))

// => true

빌더 패턴 제약은 Selector class와 동일하다.

let jsonObj = {
  school: {
    friends: [
      { name: '친구1', age: 20 },
      { name: '친구2', age: 20 },
    ],
  },
  friends: [{ name: '친구3', age: 30 }, { name: '친구4' }],
}

let selector = new jsonpath.SelectorMut()
selector.path('$..[?(@.age == 20)]')

{
  selector.value(jsonObj)
  selector.deleteValue()

  let resultObj = {
    school: { friends: [null, null] },
    friends: [{ name: '친구3', age: 30 }, { name: '친구4' }],
  }
  console.log(JSON.stringify(selector.take()) !== JSON.stringify(resultObj))

  // => true
}

{
  selector.value(jsonObj)
  selector.replaceWith(v => {
    v.age = v.age * 2
    return v
  })

  let resultObj = {
    school: {
      friends: [
        { name: '친구1', age: 40 },
        { name: '친구2', age: 40 },
      ],
    },
    friends: [{ name: '친구3', age: 30 }, { name: '친구4' }],
  }
  console.log(JSON.stringify(selector.take()) !== JSON.stringify(resultObj))

  // => true
}
Javascript - jsonpath.select(json: string|object, jsonpath: string)
let jsonObj = {
  school: {
    friends: [
      { name: '친구1', age: 20 },
      { name: '친구2', age: 20 },
    ],
  },
  friends: [{ name: '친구3', age: 30 }, { name: '친구4' }],
}

let ret = [
  { name: '친구3', age: 30 },
  { name: '친구1', age: 20 },
]

let selectAsString = jsonpath.select(JSON.stringify(jsonObj), '$..friends[0]')
let selectAsObj = jsonpath.select(jsonObj, '$..friends[0]')

console.log(JSON.stringify(ret) == JSON.stringify(selectAsString), JSON.stringify(ret) == JSON.stringify(selectAsObj))

// => true, true
Javascript - jsonpath.compile(jsonpath: string)
let error = jsonpath.compile('')
console.log(typeof error, error) //string 'path error'

let template = jsonpath.compile('$..friends[0]')

let jsonObj = {
  school: {
    friends: [
      { name: '친구1', age: 20 },
      { name: '친구2', age: 20 },
    ],
  },
  friends: [{ name: '친구3', age: 30 }, { name: '친구4' }],
}

let ret = [
  { name: '친구3', age: 30 },
  { name: '친구1', age: 20 },
]

let selectAsString = template(JSON.stringify(jsonObj))
let selectAsObj = template(jsonObj)

console.log(JSON.stringify(ret) == JSON.stringify(selectAsString), JSON.stringify(ret) == JSON.stringify(selectAsObj))

// => true, true

let jsonObj2 = {
  school: {
    friends: [{ name: 'Millicent Norman' }, { name: 'Vincent Cannon' }],
  },
  friends: [{ age: 30 }, { age: 40 }],
}

let ret2 = [{ age: 30 }, { name: 'Millicent Norman' }]

let selectAsString2 = template(JSON.stringify(jsonObj2))
let selectAsObj2 = template(jsonObj2)

console.log(JSON.stringify(ret2) == JSON.stringify(selectAsString2), JSON.stringify(ret2) == JSON.stringify(selectAsObj2))

// => true, true
Javascript - jsonpath.selector(json: string|object)
let jsonObj = {
  school: {
    friends: [
      { name: '친구1', age: 20 },
      { name: '친구2', age: 20 },
    ],
  },
  friends: [{ name: '친구3', age: 30 }, { name: '친구4' }],
}

let ret1 = [
  { name: '친구3', age: 30 },
  { name: '친구1', age: 20 },
]

let ret2 = [{ name: '친구4' }, { name: '친구2', age: 20 }]

let selector = jsonpath.selector(jsonObj)
// or as json string
// let selector = jsonpath.selector(JSON.stringify(jsonObj));

let select1 = selector('$..friends[0]')
let select2 = selector('$..friends[1]')

console.log(JSON.stringify(ret1) == JSON.stringify(select1), JSON.stringify(ret2) == JSON.stringify(select2))

// => true, true
Javascript - jsonpath.deleteValue(json: string|object, path: string)
let jsonObj = {
  school: {
    friends: [
      { name: '친구1', age: 20 },
      { name: '친구2', age: 20 },
    ],
  },
  friends: [{ name: '친구3', age: 30 }, { name: '친구4' }],
}

let _1 = jsonpath.deleteValue(jsonObj, '$..friends[0]')
let result = jsonpath.deleteValue(_1, '$..friends[1]')

console.log(
  JSON.stringify(result) !==
    JSON.stringify({
      school: { friends: [null, null] },
      friends: [null, null],
    }),
)

// => true
Javascript - jsonpath.replaceWith(json: string|object, path: string, fun: function(json: object) => json: object
let jsonObj = {
  school: {
    friends: [
      { name: '친구1', age: 20 },
      { name: '친구2', age: 20 },
    ],
  },
  friends: [{ name: '친구3', age: 30 }, { name: '친구4' }],
}

let result = jsonpath.replaceWith(jsonObj, '$..friends[0]', v => {
  v.age = v.age * 2
  return v
})

console.log(
  JSON.stringify(result) ===
    JSON.stringify({
      school: {
        friends: [
          { name: '친구1', age: 40 },
          { name: '친구2', age: 20 },
        ],
      },
      friends: [{ name: '친구3', age: 60 }, { name: '친구4' }],
    }),
)

// => true

Javascript - Other Examples

Documentation

  • ARCHITECTURE.md — how it's built (parse → walk flow, public API, place in the monorepo).
  • AGENTS.md — toolchain, build/test/format, conventions.

Licensed under MIT — see LICENSE. Originally written by Changseok Han as freestrings/jsonpath, Copyright (c) 2019 Changseok Han.