JsonPath engine written in Rust. Webassembly and Javascript support too

Overview

jsonpath_lib

Build Status crates.io npm Codecov

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

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

Rust API

jsonpath_lib crate

Go to jsonpath_lib creates.io

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!(vec![&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!(vec![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: &serde_json::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, vec![
    &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: 🇩🇪 :DeserializeOwned`>(json_str: &str, jsonpath: &str)
#[derive(Deserialize, PartialEq, Debug)]
struct Person {
    name: String,
    age: u8,
    phones: Vec<String>,
}

let ret: Vec<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: vec!["+44 1234567".to_string(), "+44 2345678".to_string()],
};

assert_eq!(ret[0], person);
Rust - jsonpath::Compiled::compile(jsonpath: &str)
let template = jsonpath::Compiled::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, vec![
    &json!({"name": "친구3", "age": 30}),
    &json!({"name": "친구1", "age": 20})
]);
Rust - jsonpath::selector(json: &serde_json::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, vec![
    &json!({"name": "친구3", "age": 30}),
    &json!({"name": "친구1", "age": 20})
]);

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

assert_eq!(json, vec![
    &json!({"name": "친구4"}),
    &json!({"name": "친구2", "age": 20})
]);
Rust - jsonpath::selector_as<T: serde: 🇩🇪 :DeserializeOwned>(json: &serde_json::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 = vec!(
    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 = vec!(
    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

Javascript API

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

Comments
  • Select for Update/Delete

    Select for Update/Delete

    Is there a way to select for update/delete?

    let result = selector
        .path("$..[?(@.age >= 30)]").unwrap()
        .value(&json_obj).delete() 
    
    question 
    opened by gkorland 11
  • replace_with call back function should be able to return an Error

    replace_with call back function should be able to return an Error

    The current callback defined:

    FnMut(&Value) -> Value
    

    Allowing the callback to return a Result will allow the callback "abort" replace in case it can't be done.

    FnMut(&Value) -> Result<Value, JsonPathError>
    

    Perhaps a new method should be added

    pub fn try_replace_with<F>(value: Value, path: &str, fun: &mut F) -> Result<Value, JsonPathError>
    where
        F: FnMut(&Value) -> Result<Value, JsonPathError>,
    
    enhancement 
    opened by gkorland 8
  • Allow gettting parse result when using `compile`

    Allow gettting parse result when using `compile`

    Currently the compile function returns impl FnMut(&Value) -> Result<Vec<&Value>, JsonPathError>. And the error of the parsing process is only evaluated when the function is called, typically when you select for data.

    However, to me it would make sense to return ParseResult<impl FnMut(&Value) -> Result<Vec<&Value>, JsonPathError>> instead and simplify the actual implementation, dropping the "match" that is re-executed every time.

    I would also do this myself, in a custom function. However the Parser is marked to be made private:

    pub use parser::Parser; // TODO private
    

    If that helps, I could create a PR to add new compile function which implements the suggested approach.

    opened by ctron 7
  • improve precompiled expression

    improve precompiled expression

    This PR adds delete and replace_with to a precompiled expression. Because the Nodes are public, this is needed for me to don't pay the compilation price every time in a hot loop.

    btw, a cargo fmt reformatted all files. Is the formatting intentionally different? Otherwise I am happy to add a fmt commit to this PR.

    opened by ritchie46 4
  • Failure to match

    Failure to match "$..['$ref']", "$..['ref']", but succeeds on "$..ref"

    Hi... I'm trying to use the JsonPath with OpenAPI files... there is a lot of redirect references that I can't extract of the form:

    {
    ...
     "$ref": "#/x/y/z",
    ...
    }
    

    Given the following JSON

    {
        "Junk1": "This is a test to illustrate use of '$' in the attr for the expression $..['$ref'] ",
        "$ref": "Match Root",
        "Subset1":[
            {"Junk2": "Data...",
             "$ref": "Match Subset1"
            }
        ],
        "hierachy1":{
            "hierachy2.1":{
                "hierachy2.1.1":{ "$ref":"Match 2.1.1"},
                "hierachy2.1.2":{ "ref":"Match 2.1.2"},
                "hierachy2.1.3":{ "ref":"No Match 2.1.3"},
                "hierachy2.1.4":{ "$ref":"Match 2.1.4"},
                "hierachy2.1.5":{ "ref":"No Match 2.1.5"}
            },
            "hierachy2.2":{
                "hierachy2.2.1":{ "ref":"No Match 2.2.1"},
                "hierachy2.2.2":{ "$ref":"Match 2.2.2"},
                "hierachy2.2.3":{ "ref":"No Match 2.2.3"},
                "hierachy2.2.4":{ "ref":"No Match 2.2.5"},
                "hierachy2.2.5":{ "$ref":"Match 2.2.5"}
            },
            "hierachy2.3":{
                "hierachy2.3.1":{ "ref":"No Match 2.3.1"},
                "hierachy2.3.2":{ "ref":"No Match 2.3.2"},
                "hierachy2.3.3":{ "ref":"No Match 2.3.3"},
                "hierachy2.3.4":{ "ref":"No Match 2.3.4"},
                "hierachy2.3.5":{ "ref":"No Match 2.3.5"},
                "hierachy2.3.6":{
                    "hierachy2.3.6.1":{ "$ref":"Match 2.3.6.1"},
                    "hierachy2.3.6.2":{ "ref":"No Match 2.3.6.2"},
                    "hierachy2.3.6.3":{ "ref":"No Match 2.3.6.3"},
                    "hierachy2.3.6.4":{ "ref":"No Match 2.3.6.4"},
                    "hierachy2.3.6.5":{ "ref":"No Match 2.3.6.5"}
                    }
                }
        }
    }
    

    Using the online JasonPath evaluator, The expressions "$..['$ref']", "$..[$ref]", "$..$ref" should yeild: The

    Select: [String("Match Root")
    String("Match Subset1"),
    String("Match 2.1.1"),
    String("Match 2.1.4"),
    String("Match 2.2.2"),
    String("Match 2.2.5"),
    String("Match 2.3.6.1")]
    

    the expression "$..$ref" causes an error: Select: Err(path error: $.. ^^^ )

    This works: "$..ref"

    Select: [String("Match 2.1.2"), String("No Match 2.1.3"), String("No Match 2.1.5"), String("No Match 2.2.1"), String("No Match 2.2.3"), String("No Match 2.2.5"), String("No Match 2.3.1"), String("No Match 2.3.2"), String("No Match 2.3.3"), String("No Match 2.3.4"), String("No Match 2.3.5"), String("No Match 2.3.6.2"), String("No Match 2.3.6.3"), String("No Match 2.3.6.4"), String("No Match 2.3.6.5")]
    

    I'll be happy to contribute, if you have some indicator on where to look/fix JR

    bug 
    opened by JRAndreassen 4
  • Bracket notation after recursive descent does not recurse

    Bracket notation after recursive descent does not recurse

    Selector: $..[0]

    Input:

    ["first", {"key": ["first nested", {"more": [{"nested": ["deepest", "second"]}, ["more", "values"]]}]}]
    

    Expected output:

    ["deepest", "first nested", "first", "more", {"nested": ["deepest", "second"]}]
    

    Actual output:

    ["first"]
    

    Compare https://cburgmer.github.io/json-path-comparison/. For reference, the output was generated by the program in https://github.com/cburgmer/json-path-comparison/tree/master/implementations/Rust_jsonpath_lib.

    bug 
    opened by cburgmer 3
  • Improve Parser and Tokenizer performance

    Improve Parser and Tokenizer performance

    When profiling the compile function you can see that a lot of time is wasted on memory allocations. It seems like most of them can be avoided it the the Parser and the Tokenizer will try to work with slices from the original path and not allocate new Strings

    image

    ref https://github.com/RedisJSON/RedisJSON/issues/424 & https://github.com/RedisJSON/RedisJSON/issues/425

    enhancement 
    opened by gkorland 2
  • New release on crates.io?

    New release on crates.io?

    Hello,

    I'm working on a project that pulls in jsonpath_lib as a transitive dependency, and jsonpath's unexpected dependency on env_logger causes cargo-deny conflicts:

    error[B004]: found 2 duplicate entries for crate 'env_logger'
       │  
    30 │ ╭ env_logger 0.7.1 registry+https://github.com/rust-lang/crates.io-index
    31 │ │ env_logger 0.8.3 registry+https://github.com/rust-lang/crates.io-index
       │ ╰──────────────────────────────────────────────────────────────────────^ lock entries
       │  
    

    I see that this dependency has been removed in https://github.com/freestrings/jsonpath/pull/66.

    Are you planning to do a release sometime soon? I'd love to be able to be able to avoid the unnecessary dependency in my release code. Please let me know if there's anything I can do to make this easier :) Thanks!

    opened by olix0r 2
  • Move env-logger to dev-dependencies

    Move env-logger to dev-dependencies

    Just noticed this dependency cropped up in my application through cargo tree -d.

    Since (as far as I understand) this is just a library and all references of env-logger I found are in tests, it should be moved to [dev-dependencies].

    On my local both cargo build and cargo test succeed (with rustc 1.50).

    opened by aquarhead 1
  • More flexible API

    More flexible API

    Hi, thank you for the library!

    I am trying to use select with Vec<Rc<serde_json::Value>>, but it seems that the only option I have now is to construct a new array-like serde_json::Value. What about adding (or even replacing existing select methods) new pub trait for navigating in json or some other more flexible API? F.e. wolker that can in-depth and in-width move across json could suit here.

    opened by mikevoronov 1
  • Make JsonPathError implement std::error::Error

    Make JsonPathError implement std::error::Error

    Make JsonPathError implement std::error::Error so it can be encapsulated as a valid source by libraries or programs that implement their own error type. Specifically this is usefull when using thiserror, for example now we can have the following error type in our program that uses jsonpath:

    use thiserror::Error;
    
    #[derive(Error, Debug)]
    pub enum MyError {
        #[error("General error: {0}")]
        GeneralError(String),
    
        #[error("JSON path error {0}")]
        InvalidJsonPath(#[from] jsonpath_lib::JsonPathError),
    
        #[error("Some other error")]
        SomeOtherError,
    }
    
    opened by yoav-steinberg 1
  • Duplicate results no filter

    Duplicate results no filter

    Filter might return duplicate results when the internal objects are similar.

    e.g. input JSON both objects have name == {"first":"A","middle":"A"}

    [{{"name":{"first":"A","middle":"A"},"rank":8},{"name":{"first":"A","middle":"A"},"rank":90}]
    

    When running:

    $[?($.name.first=="A")]
    

    The following result is returned:

    [{{"name":{"first":"A","middle":"A"},"rank":8},{"name":{"first":"A","middle":"A"},"rank":8},{{"name":{"first":"A","middle":"A"},"rank":90},{"name":{"first":"A","middle":"A"},"rank":90}]
    

    It seems like the bug is in this code which compares all the candidates with all values and return each "parent" twice. https://github.com/freestrings/jsonpath/blob/1a84c5af9445e617a6deed14dadfaee13af0d95f/src/select/expr_term.rs#L107

    ref https://github.com/RedisJSON/RedisJSON/issues/667

    opened by gkorland 0
  • Fails to match with nested query selector

    Fails to match with nested query selector

    Path: $[*][?(@.inner.for.inner=='u8')]

    JSON:

    {
        "0:4": {
          "id": "0:4",
          "inner": {
            "for": {"inner": "u8", "kind": "primitive"}
          }
        }
    }
    

    jsonpath matches to []

    Expected:

    [
       {
          "id" : "0:4",
          "inner" : {
             "for" : {
                "inner" : "u8",
                "kind" : "primitive"
             }
          }
       }
    ]
    

    (from jayway, via https://jsonpath.herokuapp.com/)

    opened by aDotInTheVoid 0
  • Parser should throw an error on surplus text following the closing angle bracket of an array index

    Parser should throw an error on surplus text following the closing angle bracket of an array index

    Path such as $.store.book[0]category Does not throw an error and is silently ignoring the surplus text category beyond the ] And is parsed as $.store.book[0]

    Can be demonstrated also on https://freestrings.github.io/jsonpath/ The same value is returned with and without the surplus text category. Parser should throw an error on surplus text.

    Notice that If there is a dot delimiter before the surplus text then everything is OK, e.g., $.store.book[0].category is working as expeced.

    opened by oshadmi 0
  • Filter with OR expression fails with non-existing value

    Filter with OR expression fails with non-existing value

    Adding a test such as the following, fails when a filter contains an OR expression with one of its operands being compared to a none-existing value, e.g., Slightly modifying an existing test named op_object_or_default in op.rs:

    #[test]
    fn op_object_or_nonexisting_default() {
        setup();
    
        select_and_then_compare(
            "$.friends[?(@.id >= 2 || @.id == 4)]",
            read_json("./benchmark/data_obj.json"),
            json!([
                { "id" : 2, "name" : "Gray Berry" }
            ]),
        );
    }
    

    The selected result is empty, while it should be equal to the target json.

    When removing the right operand || @.id == 4 it succeeds (with filter "$.friends[?(@.id >= 2)]" )

    opened by oshadmi 0
Releases(v0.3.0)
  • v0.3.0(Jun 3, 2021)

  • v0.2.6(Dec 16, 2020)

  • v0.2.5(Apr 15, 2020)

    • fix #37 Unit tests cleanup
    • fix #38 Bracket notation not supported inside filter expression
    • fix #39 Empty result for filter expression returns array of null
    • fix #40 Bracket notation after recursive descent does not recurse
    • fix #43 Failure to match "$..['']", "$..['ref']", but succeeds on $..ref
    Source code(tar.gz)
    Source code(zip)
  • v0.2.4(Feb 14, 2020)

  • v0.2.3(Jun 24, 2019)

    Bugs

    • Invalid wildcard filter results #7
    • fix broken build in osx. remove neon-serde be29571

    Etc

    • remove indexmap crate 28ad9c9
    • bump library version up
      • cfg-if
      • console_error_panic_hook
      • we_alloc
      • env_logger
      • array_tool
    Source code(tar.gz)
    Source code(zip)
  • v0.2.2(Jun 20, 2019)

    New Feature

    array filter

    • step 74666d2
    • multiple keys de97e2f
    • escaped quote notation 51deec6

    Etc

    • improve error message fff0e86

    Bugs

    • Results do not match other implementations #6
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Jun 11, 2019)

    New feature

    • delete, replace

    Changed

    • &Value is default return type

    Removed feature

    • map function
    • filter module
    • ref_value module

    Etc

    • jsonpath::select performance enhancement
    Source code(tar.gz)
    Source code(zip)
  • v0.1.10(Apr 13, 2019)

    jsonpath_lib v0.1.10

    • update README.md

    jsonpath-wasm v0.1.3

    • npm package publish
    • add wasm-bingen-test unit test

    jsonpath-rs v0.1.9

    • fix README.md link path
    Source code(tar.gz)
    Source code(zip)
  • v0.1.9.2(Apr 10, 2019)

    *Rust jsonpath_lib v0.1.9

    • bugfix: d955a16 d75b936 fix array filter
    • new feature: 30aa383 Selector struct

    *NodeJs jsonpath-rs v0.1.7

    • new feature: d263e30 Selector class
    Source code(tar.gz)
    Source code(zip)
  • v0.1.8(Apr 5, 2019)

    *NodeJs jsonpath-rs v.0.1.6

    • select(json: string|object, jsonpath: string)
    • compile(jsonpath: string)
    • selector(json: string|object)
    • alloc_json, dealloc_json

    *Rust jsontpath_lib v0.1.8

    • select(json: &serde_json::value::Value, jsonpath: &str)
    • select_as_str(json_str: &str, jsonpath: &str)
    • select_as<T: serde::de::DeserializeOwned>(json_str: &str, jsonpath: &str)
    • compile(jsonpath: &str)
    • selector(json: &serde_json::value::Value)
    • selector_as<T: serde::de::DeserializeOwned>(json: &serde_json::value::Value)
    Source code(tar.gz)
    Source code(zip)
Owner
Changseok Han
Changseok Han
Rust query string parser with nesting support

What is Queryst? This is a fork of the original, with serde and serde_json updated to 0.9 A query string parsing library for Rust inspired by https://

Stanislav Panferov 67 Nov 16, 2022
🕑 A personal git log and MacJournal output parser, written in rust.

?? git log and MacJournal export parser A personal project, written in rust. WORK IN PROGRESS; NOT READY This repo consolidates daily activity from tw

Steven Black 4 Aug 17, 2022
A CSS parser, transformer, and minifier written in Rust.

@parcel/css A CSS parser, transformer, and minifier written in Rust. Features Extremely fast – Parsing and minifying large files is completed in milli

Parcel 3.1k Jan 9, 2023
A WIP svelte parser written in rust. Designed with error recovery and reporting in mind

Svelte(rs) A WIP parser for svelte files that is designed with error recovery and reporting in mind. This is mostly a toy project for now, with some v

James Birtles 3 Apr 19, 2023
PEG parser for YAML written in Rust 🦀

yaml-peg PEG parser (pest) for YAML written in Rust ?? Quick Start ⚡️ # Run cargo run -- --file example_files/test.yaml # Output { "xmas": "true",

Visarut Phusua 4 Sep 17, 2022
MRT/BGP data parser written in Rust.

BGPKIT Parser BGPKIT Parser aims to provides the most ergonomic MRT/BGP message parsing Rust API. BGPKIT Parser has the following features: performant

BGPKIT 46 Dec 19, 2022
rbdt is a python library (written in rust) for parsing robots.txt files for large scale batch processing.

rbdt ?? ?? ?? ?? rbdt is a work in progress, currently being extracted out of another (private) project for the purpose of open sourcing and better so

Knuckleheads' Club 0 Nov 9, 2021
gors is an experimental go toolchain written in rust (parser, compiler).

gors gors is an experimental go toolchain written in rust (parser, compiler). Install Using git This method requires the Rust toolchain to be installe

Aymeric Beaumet 12 Dec 14, 2022
A WIP minimal C Compiler written in Rust 🦀

_ _ ____ ____ | | __ _ _ __ | | __ / ___/ ___| _ | |/ _` | '_ \| |/ / | | | | | |_| | (_| | | | | < | |__| |___

null 5 Oct 26, 2022
Blazingly fast function selector miner written in Rust.

About Blazingly fast function selector miner written in Rust. Usage git clone [email protected]:kadenzipfel/function-selector-miner.git cd function-selec

kaden 38 Apr 13, 2023
A handwritten fault-tolerant, recursive-descent parser for PHP written in Rust.

PHP-Parser A handwritten fault-tolerant, recursive-descent parser for PHP written in Rust. Warning - this is still alpha software and the public API i

PHP Rust Tools 278 Jun 24, 2023
Pure, simple and elegant HTML parser and editor.

HTML Editor Pure, simple and elegant HTML parser and editor. Examples Parse HTML segment/document let document = parse("<!doctype html><html><head></h

Lomirus 16 Nov 8, 2022
A native Rust port of Google's robots.txt parser and matcher C++ library.

robotstxt A native Rust port of Google's robots.txt parser and matcher C++ library. Native Rust port, no third-part crate dependency Zero unsafe code

Folyd 72 Dec 11, 2022
Parsing and inspecting Rust literals (particularly useful for proc macros)

litrs: parsing and inspecting Rust literals litrs offers functionality to parse Rust literals, i.e. tokens in the Rust programming language that repre

Lukas Kalbertodt 31 Dec 26, 2022
A Rust crate for RDF parsing and inferencing.

RDF-rs This crate provides the tools necessary to parse RDF graphs. It currently contains a full (with very few exceptions) Turtle parser that can par

null 2 May 29, 2022
Yet Another Parser library for Rust. A lightweight, dependency free, parser combinator inspired set of utility methods to help with parsing strings and slices.

Yap: Yet another (rust) parsing library A lightweight, dependency free, parser combinator inspired set of utility methods to help with parsing input.

James Wilson 117 Dec 14, 2022
Sqllogictest parser and runner in Rust.

Sqllogictest-rs Sqllogictest parser and runner in Rust. License Licensed under either of Apache License, Version 2.0 (LICENSE-APACHE or http://www.apa

Singularity Data Inc. 101 Dec 21, 2022
A library to display rich (Markdown) snippets and texts in a rust terminal application

A CLI utilities library leveraging Markdown to format terminal rendering, allowing separation of structure, data and skin. Based on crossterm so works

Canop 614 Dec 29, 2022
Rust grammar tool libraries and binaries

Grammar and parsing libraries for Rust grmtools is a suite of Rust libraries and binaries for parsing text, both at compile-time, and run-time. Most u

Software Development Team 318 Dec 26, 2022