mirror of
https://github.com/serde-rs/json.git
synced 2026-02-05 15:36:17 +00:00
Auto merge of #41 - pyfisch:json-pointer, r=erickt
feat(value): implement RFC6901 JSON Pointer Add a method `pointer(&str)` to `Value`. Deprecate `lookup(&str)`. Bump version to 0.7.1. Closes #9 Notes: * It should be possible to add a `pointer_mut(&str)` method to Value. This would allow to add and modify values. (Maybe even a delete method) I failed to add such a method because of borrow checker. * Should [RFC6902 JSON Patch](https://tools.ietf.org/html/rfc6902) be implemented or is this something for a separate crate? (Patch is based on Pointer)
This commit is contained in:
commit
aa427ae1cc
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_json"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "A JSON serialization file format"
|
||||
|
||||
@ -98,6 +98,8 @@ impl Value {
|
||||
Some(target)
|
||||
}
|
||||
|
||||
/// **Deprecated**: Use `Value.pointer()` and pointer syntax instead.
|
||||
///
|
||||
/// Looks up a value by path.
|
||||
///
|
||||
/// This is a convenience method that splits the path by `'.'`
|
||||
@ -120,6 +122,46 @@ impl Value {
|
||||
Some(target)
|
||||
}
|
||||
|
||||
/// Looks up a value by a JSON Pointer.
|
||||
///
|
||||
/// JSON Pointer defines a string syntax for identifying a specific value
|
||||
/// within a JavaScript Object Notation (JSON) document.
|
||||
///
|
||||
/// A Pointer is a Unicode string with the reference tokens separated by `/`.
|
||||
/// Inside tokens `/` is replaced by `~1` and `~` is replaced by `~0`. The
|
||||
/// addressed value is returned and if there is no such value `None` is
|
||||
/// returned.
|
||||
///
|
||||
/// For more information read [RFC6901](https://tools.ietf.org/html/rfc6901).
|
||||
pub fn pointer<'a>(&'a self, pointer: &str) -> Option<&'a Value> {
|
||||
fn parse_index(s: &str) -> Option<usize> {
|
||||
if s.starts_with("+") || (s.starts_with("0") && s.len() != 1) {
|
||||
return None
|
||||
}
|
||||
s.parse().ok()
|
||||
}
|
||||
if pointer == "" {
|
||||
return Some(self);
|
||||
}
|
||||
if !pointer.starts_with('/') {
|
||||
return None;
|
||||
}
|
||||
let mut target = self;
|
||||
for escaped_token in pointer.split('/').skip(1) {
|
||||
let token = escaped_token.replace("~1", "/").replace("~0", "~");
|
||||
let target_opt = match target {
|
||||
&Value::Object(ref map) => map.get(&token[..]),
|
||||
&Value::Array(ref list) => parse_index(&token[..])
|
||||
.and_then(|x| list.get(x)),
|
||||
_ => return None,
|
||||
};
|
||||
if let Some(t) = target_opt {
|
||||
target = t;
|
||||
} else { return None }
|
||||
}
|
||||
Some(target)
|
||||
}
|
||||
|
||||
/// If the `Value` is an Object, performs a depth-first search until
|
||||
/// a value associated with the provided key is found. If no value is found
|
||||
/// or the `Value` is not an Object, returns None.
|
||||
|
||||
@ -1441,3 +1441,40 @@ fn test_json_stream_empty() {
|
||||
|
||||
assert!(parsed.next().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_json_pointer() {
|
||||
// Test case taken from https://tools.ietf.org/html/rfc6901#page-5
|
||||
let data: Value = serde_json::from_str(r#"{
|
||||
"foo": ["bar", "baz"],
|
||||
"": 0,
|
||||
"a/b": 1,
|
||||
"c%d": 2,
|
||||
"e^f": 3,
|
||||
"g|h": 4,
|
||||
"i\\j": 5,
|
||||
"k\"l": 6,
|
||||
" ": 7,
|
||||
"m~n": 8
|
||||
}"#).unwrap();
|
||||
assert_eq!(data.pointer("").unwrap(), &data);
|
||||
assert_eq!(data.pointer("/foo").unwrap(),
|
||||
&Value::Array(vec![Value::String("bar".to_owned()),
|
||||
Value::String("baz".to_owned())]));
|
||||
assert_eq!(data.pointer("/foo/0").unwrap(),
|
||||
&Value::String("bar".to_owned()));
|
||||
assert_eq!(data.pointer("/").unwrap(), &Value::U64(0));
|
||||
assert_eq!(data.pointer("/a~1b").unwrap(), &Value::U64(1));
|
||||
assert_eq!(data.pointer("/c%d").unwrap(), &Value::U64(2));
|
||||
assert_eq!(data.pointer("/e^f").unwrap(), &Value::U64(3));
|
||||
assert_eq!(data.pointer("/g|h").unwrap(), &Value::U64(4));
|
||||
assert_eq!(data.pointer("/i\\j").unwrap(), &Value::U64(5));
|
||||
assert_eq!(data.pointer("/k\"l").unwrap(), &Value::U64(6));
|
||||
assert_eq!(data.pointer("/ ").unwrap(), &Value::U64(7));
|
||||
assert_eq!(data.pointer("/m~0n").unwrap(), &Value::U64(8));
|
||||
// Invalid pointers
|
||||
assert!(data.pointer("/unknown").is_none());
|
||||
assert!(data.pointer("/e^f/ertz").is_none());
|
||||
assert!(data.pointer("/foo/00").is_none());
|
||||
assert!(data.pointer("/foo/01").is_none());
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user