diff --git a/src/value/mod.rs b/src/value/mod.rs index 4793e93ec..3d33b13e9 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -828,6 +828,69 @@ impl Value { }) } + /// Removes a value by a JSON Pointer and returns that value. + /// + /// 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). + /// + /// # Example of Use + /// + /// ``` + /// # use serde_json::{Value, json}; + /// # + /// let mut data = json!({ + /// "x": { + /// "y": ["z", "zz"] + /// } + /// }); + /// + /// let v = data.remove_by_pointer("/x/y/0"); + /// assert_eq!(v, Some(json!("z"))); + /// assert_eq!( + /// data, + /// json!({ + /// "x": { + /// "y": ["zz"] + /// } + /// }), + /// ); + /// + /// let v = data.remove_by_pointer("/x/y"); + /// assert_eq!(v, Some(json!(["zz"]))); + /// assert_eq!(data, json!({ "x": {} })); + /// + /// let v = data.remove_by_pointer(""); + /// assert_eq!(v, Some(json!({ "x": {} }))); + /// assert_eq!(data, Value::Null); + /// ``` + pub fn remove_by_pointer(&mut self, pointer: &str) -> Option { + if pointer.is_empty() { + return Some(self.take()); + } + #[allow(clippy::manual_split_once)] + let mut pointer_split = pointer.rsplitn(2, '/'); + let key = pointer_split.next()?; + let pointer = pointer_split.next()?; + self.pointer_mut(pointer).and_then(|value| match value { + Value::Object(map) => map.remove(key), + Value::Array(list) => parse_index(key).and_then(move |x| { + if x < list.len() { + Some(list.remove(x)) + } else { + None + } + }), + _ => None, + }) + } + /// Takes the value out of the `Value`, leaving a `Null` in its place. /// /// ```