Как я могу объединить два объекта JSON с Rust?
У меня есть два файла JSON:
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" ]
}
Я хочу объединить #2 с #1, где #2 переопределяет #1, производя следующий вывод:
{
"title": "This is another title",
"person" : {
"firstName" : "Jane",
"lastName" : "Doe"
},
"cities":[ "colombo" ]
}
Я проверил json-патч crate, который делает это, но он не компилируется со стабильным Rust. Можно ли сделать что-то подобное с чем-то вроде serde_json и стабильного Rust?
2 ответа
Размещение ответа, предложенного Шепмастером ниже
#[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);
}
Поскольку вы хотели использовать json-patch, я предполагаю, что вы специально искали реализацию JSON Merge Patch (RFC 7396), которую реализует этот ящик. В этом случае при слиянии объекта должны быть сброшены те ключи, соответствующие значения которых в патче null
, которые примеры кода в других ответах не реализуют.
Код, который объясняет это, приведен ниже. Я изменил патч, чтобы удалить person.lastName
ключ, установив его null
как демонстрация. Это также не нужно unwrap()
Option
вернулся as_object_mut()
,
#[macro_use]
extern crate serde_json;
use serde_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);
}
Ожидаемый результат
{
"cities": [
"colombo"
],
"person": {
"firstName": "Jane"
},
"title": "This is a title"
}
уведомление person.lastName
был сброшен
Это сработало для меня
#[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);
}