简体   繁体   English

如何组合(包括嵌套数组值)两个 serde_yaml::Value 对象?

[英]how to combine (including nested array values) two serde_yaml::Value objects?

I am having trouble creating a recursive function to parse two serde_yaml::Value variables and combine them.我无法创建递归 function 来解析两个 serde_yaml::Value 变量并将它们组合起来。 It's easy enough to combine them at a base-level object, but then the sublevel values are only those of the combined value.在基本级别 object 中组合它们很容易,但是子级别值只是组合值的那些值。

Given:鉴于:

let original:serde_yaml::Value = serde_yaml::from_str(r#"
keyA:
  subKeyA:
    - A
    - B
    - C
keyB: "one"
keyC: "a"
"#
).unwrap();

let add_or_modify_these_values:serde_yaml::Value = serde_yaml::from_str(r#"
keyA:
  subKeyA:
    - D
  subKeyB:
    - BA
keyB: "two"
keyC:
  - A
  - B
"#
).unwrap();

How would I combine them so all nested properties are accounted for, eg:我将如何组合它们以便考虑所有嵌套属性,例如:

keyA:
  subKeyA:
    - A
    - B
    - C
    - D
  subKeyB:
    - BA
keyB: "two"
keyC:
  - A
  - B

When there are complications (for example, different value types like keyC) I'd prefer overwriting the original value type with the new one.当出现复杂情况时(例如,像 keyC 这样的不同值类型),我更愿意用新值类型覆盖原始值类型。

Edit: I've also looked at a similar question for json here: How can I merge two JSON objects with Rust?编辑:我也在此处查看了 json 的类似问题: How can I merge two JSON objects with Rust? but that merge method will not combine array values, only overwrite.但该合并方法不会合并数组值,只会覆盖。

Edit: Proper answer is marked.编辑:已标记正确答案。 Will leave this one for the JSON version.将把这个留给 JSON 版本。


The json version: json版本:

fn merge(a: &mut serde_json::Value, b: serde_json::Value) {
    match (a, b) {
        (a @ &mut serde_json::Value::Object(_), serde_json::Value::Object(b)) => {
            let a = a.as_object_mut().unwrap();
            for (k, v) in b {
                if v.is_array() && a.contains_key(&k) && a.get(&k).as_ref().unwrap().is_array() {
                           let mut _a = a.get(&k).unwrap().as_array().unwrap().to_owned();
                           _a.append(&mut v.as_array().unwrap().to_owned());
                           a[&k] = serde_json::Value::from(_a);
                }
                else{   
                    merge(a.entry(k).or_insert(serde_json::Value::Null), v);
                }
            }
        }
        (a, b) => *a = b,
    }
}

I've figured out the conversion below (could possibly use some cleanup):我已经弄清楚了下面的转换(可能需要一些清理):

fn merge_yaml(a: &mut serde_yaml::Value, b: serde_yaml::Value) {
    match (a, b) {
        (a @ &mut serde_yaml::Value::Mapping(_), serde_yaml::Value::Mapping(b)) => {
            let a = a.as_mapping_mut().unwrap();
            for (k, v) in b {
                if v.is_sequence() && a.contains_key(&k) && a[&k].is_sequence() { 
                    let mut _b = a.get(&k).unwrap().as_sequence().unwrap().to_owned();
                    _b.append(&mut v.as_sequence().unwrap().to_owned());
                    a[&k] = serde_yaml::Value::from(_b);
                    continue;
                }
                if !a.contains_key(&k) {a.insert(k.to_owned(), v.to_owned());}
                else { merge_yaml(&mut a[&k], v); }

            }
            
        }
        (a, b) => *a = b,
    }
}

Here's a cleaned-up version (used with #![feature(let_chains)] ):这是一个清理过的版本(与#![feature(let_chains)]使用):

    fn merge_yaml(a: &mut serde_yaml::Value, b: serde_yaml::Value) {
        match (a, b) {
            (serde_yaml::Value::Mapping(ref mut a), serde_yaml::Value::Mapping(b)) => {
                for (k, v) in b {
                    if let Some(b_seq) = v.as_sequence()
                        && let Some(a_val) = a.get(&k)
                        && let Some(a_seq) = a_val.as_sequence()
                    {
                        a[&k] = [a_seq.as_slice(), b_seq.as_slice()].concat().into();
                        continue;
                    }

                    if !a.contains_key(&k) {
                        a.insert(k, v);
                    }
                    else {
                        Self::merge_yaml(&mut a[&k], v);
                    }
                }

            }
            (a, b) => *a = b,
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM