I have two JSON files:
JSON 1
{
"title": "This is a title",
"person" : {
"firstName" : "John",
"lastName" : "Doe"
},
"cities":[ "london", "paris" ]
}
JSON 2
{
"title": "This is another title",
"person" : {
"firstName" : "Jane"
},
"cities":[ "colombo" ]
}
I want to merge #2 into #1 where #2 overrides #1, producing following output:
{
"title": "This is another title",
"person" : {
"firstName" : "Jane",
"lastName" : "Doe"
},
"cities":[ "colombo" ]
}
I checked out the crate json-patch which does this but it does not compile against stable Rust. Is it possible to do something similar with something like serde_json and stable Rust?
Since you wanted to use json-patch, I assume you were looking specifically for a JSON Merge Patch (RFC 7396) implementation since that is what that crate implements. In that case, merging an object should unset those keys whose corresponding value in the patch is null
, which the code samples in the other answers do not implement.
The code that accounts for that is below. I modified the patch to delete the person.lastName
key by setting it to null
as a demonstration. It also does not need to unwrap()
the Option
returned by as_object_mut()
, unlike one of the other answers.
use serde_json::{json, Value};
fn merge(a: &mut Value, b: Value) {
if let Value::Object(a) = a {
if let Value::Object(b) = b {
for (k, v) in b {
if v.is_null() {
a.remove(&k);
}
else {
merge(a.entry(k).or_insert(Value::Null), v);
}
}
return;
}
}
*a = b;
}
fn main() {
let mut a = json!({
"title": "This is a title",
"person" : {
"firstName" : "John",
"lastName" : "Doe"
},
"cities":[ "london", "paris" ]
});
let b = json!({
"title": "This is another title",
"person" : {
"firstName" : "Jane",
"lastName": null
},
"cities":[ "colombo" ]
});
merge(&mut a, b);
println!("{:#}", a);
}
The expected output is
{
"cities": [
"colombo"
],
"person": {
"firstName": "Jane"
},
"title": "This is another title"
}
Notice person.lastName
has been unset.
Placing the answer suggested by Shepmaster below
#[macro_use]
extern crate serde_json;
use serde_json::Value;
fn merge(a: &mut Value, b: Value) {
match (a, b) {
(a @ &mut Value::Object(_), Value::Object(b)) => {
let a = a.as_object_mut().unwrap();
for (k, v) in b {
merge(a.entry(k).or_insert(Value::Null), v);
}
}
(a, b) => *a = b,
}
}
fn main() {
let mut a = json!({
"title": "This is a title",
"person" : {
"firstName" : "John",
"lastName" : "Doe"
},
"cities":[ "london", "paris" ]
});
let b = json!({
"title": "This is another title",
"person" : {
"firstName" : "Jane"
},
"cities":[ "colombo" ]
});
merge(&mut a, b);
println!("{:#}", a);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With