Let's say I have the JSON below (JSON 1)
{
"title": "This is a title",
"person" : {
"firstName" : "John",
"lastName" : "Doe"
},
"cities":[ "london", "paris" ]
}
And another as follows (JSON 2)
{
"title": "This is another title",
"person" : {
"firstName" : "Jane"
},
"cities":[ "colombo" ]
}
How can I get the following output? (merging 2 into 1 where 2 Overrides 1)
{
"title": "This is another title",
"person" : {
"firstName" : "Jane",
"lastName" : "Doe"
},
"cities":[ "colombo" ]
}
I did checkout the crate json-patch which does this but it does not compile against stable rust. I want to know if its possible to do something similar with serde.
If you parse both pieces of JSON to the serde_json::Value enum then you can call as_object_mut or use if let to destructure the values to Maps. You can then use extend on the first Map with the second Map as the argument. I believe that should result in a Map instance that matches what you describe. You can then construct a new Value::Object(map1) and serde_json::to_string or to_writer with that Value.
Here is one possible implementation. I haven't tested it thoroughly but it works for your example.
#[macro_use]
extern crate serde_json;
use serde_json::Value;
fn merge(a: &mut Value, b: &Value) {
match (a, b) {
(&mut Value::Object(ref mut a), &Value::Object(ref b)) => {
for (k, v) in b {
merge(a.entry(k.clone()).or_insert(Value::Null), v);
}
}
(a, b) => {
*a = b.clone();
}
}
}
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);
}
@commandline Thank you for your suggestion.
@dtolnay Yours worked perfectly. Thank you!. Any Gotchas in your code I should know about? I'm still learning Rust.
I don't think there are gotchas but depending on how the rest of your code is structured and specifically depending on whether you have ownership of a and/or b, you may be able to come up with a more efficient implementation. For example if you have ownership of b then you may be able to move "This is another title" instead of cloning it.
Most helpful comment
Here is one possible implementation. I haven't tested it thoroughly but it works for your example.