首页 > 解决方案 > 如何组合(包括嵌套数组值)两个 serde_yaml::Value 对象?

问题描述

我无法创建一个递归函数来解析两个 serde_yaml::Value 变量并将它们组合起来。将它们组合在一个基本级别的对象上很容易,但是子级别的值只是组合值的值。

鉴于:

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();

我将如何组合它们以便考虑所有嵌套属性,例如:

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

当出现复杂情况时(例如,不同的值类型,如 keyC),我宁愿用新的值类型覆盖原始值类型。

编辑:我也在这里查看了 json 的类似问题:如何将两个 JSON 对象与 Rust 合并? 但是该合并方法不会合并数组值,只会覆盖。

标签: rustyamlserde

解决方案


这是一个清理后的版本(与 一起使用#![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,
        }
    }

推荐阅读