Yaml-cpp(新API):在序列中混合映射和标量时出现问题

Yaml-cpp (new API): Problems mixing maps and scalars in a sequence

本文关键字:映射 混合 标量 问题 API Yaml-cpp      更新时间:2023-10-16

解析这种形式的yaml文件时,我有一个非常简单的问题:

- Foo
- Bar:
   b1: 5

我想将顶级键解析为字符串,即"Foo"和"Bar"。如您所见,序列中的第一个条目是标量,第二个条目是包含一个键/值对的映射。 假设我已将此 YAML 文本加载到名为 config 的节点中。 我通过以下方式迭代配置:

YAML::Node::const_iterator n_it = config.begin();
for (; n_it != config.end(); n_it++) {
    std::string name;
    if (n_it->Type() == YAML::NodeType::Scalar)
        name = n_it->as<std::string>();
    else if (n_it->Type() == YAML::NodeType::Map) {
        name = n_it->first.as<std::string>();
    }
}

问题是解析第二个"Bar"条目。 我收到以下 yaml-cpp 异常,告诉我我正在尝试从序列迭代器n_it访问密钥。

YAML::InvalidNode: yaml-cpp: error at line 0, column 0: invalid node; this may result from using a map iterator as a sequence iterator, or vice-versa

如果我更改对此的访问权限:

name = n_it->as<std::string>();

我得到一个不同的 yaml-cpp 异常,我想这是因为我试图以 std::string 的形式访问整个地图

YAML::TypedBadConversion<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >: yaml-cpp: error at line 0, column 0: bad conversion

有人可以向我解释出了什么问题吗?

编辑:新问题我仍然在这个 API 处理地图与序列时遇到问题。 现在假设我有以下结构:

foo_map["f1"] = "one";
foo_map["f2"] = "two";
bar_map["b1"] = "one";
bar_map["b2"] = "two";

我希望将其转换为以下 YAML 文件:

Node: 
    - Foo:
      f1 : one
      f2 : two
    - Bar:
      b1 : one
      b2 : two

我会这样做:

node.push_back("Foo");
node["Foo"]["b1"] = "one";
...
node.push_back("Bar");

但是,在最后一行节点现在已经从序列转换为映射,我得到了一个例外。 我能做到这一点的唯一方法是输出地图:

Node:
    Foo:
      f1 : one
      f2 : two
    Bar:
      b1 : one
      b2 : two

问题是如果我无法读回此类文件。 如果我遍历 Node,我什至无法在没有异常的情况下获取节点迭代器的类型。

YAML::Node::const_iterator n_it = node.begin();
for (; n_it != config.end(); n_it++) {
        if (n_it->Type() == YAML::NodeType::Scalar) {
            // throws exception
        }
    }

这应该很容易处理,但一直让我发疯!

在你的表达中

name = n_it->first.as<std::string>();

n_it是一个序列迭代器(因为它是顶级节点的迭代器(,您刚刚建立的序列迭代器指向映射。那是

YAML::Node n = *n_it;

是一个映射节点。此映射节点(在您的示例中(如下所示:

Bar:
  b1: 5

换句话说,它具有单个键/值对,键是字符串,值是映射节点。听起来你想要字符串键。所以:

assert(n.size() == 1);  // Verify that there is, in fact, only one key/value pair
YAML::Node::const_iterator sub_it = n.begin();  // This iterator points to
                                                // the single key/value pair
name = sub_it->first.as<std::string>();
Sample.yaml
config:
  key1: "SCALER_VAL" # SCALER ITEM
  key2: ["val1", "val2"] #SEQUENCE ITEM
  key3: # MAP ITEM
    nested_key1: "nested_val"

#SAMPLE CODE for Iterate Yaml Node;
YAML::Node internalconfig_yaml = YAML::LoadFile(configFileName);
const YAML::Node &node = internalconfig_yaml["config"];
for(const auto& it : node )
{
    std::cout << "nnested Key: " << it.first.as<std::string>() << "n";
    if (it.second.Type() == YAML::NodeType::Scalar)
    {
        std::cout << "nnested value: " << std::to_string(it.second.as<int>()) << "n";
    }
    if (it.second.Type() == YAML::NodeType::Sequence)
    {
        std::vector<std::string> temp_vect;
        const YAML::Node &nestd_node2 = it.second;
        for(const auto& it2 : nestd_node2)
        {
            if (*it2)
            {
                std::cout << "nnested sequence value: " << it2.as<std::string>() << "n";
                temp_vect.push_back(it2.as<std::string>());
             }
        }
        std::ostringstream oss;
        std::copy(temp_vect.begin(), temp_vect.end(),                 
                  std::ostream_iterator<std::string>(oss, ","));
        std::cout << "nnested sequence as string: " <<oss.str() << "n";
    }
    if (it2.second.Type() == YAML::NodeType::Map)
    {
    // Iterate Recursively again !!
    }
}

有关更多详细信息,请参阅此处;

这也可以通过新的C++循环来完成:

      std::string name;
      for (const auto &entry: node_x) {
        assert(name.empty());
        name = entry.first.as<std::string>();
      }

如果node_x不是您想象的,则会触发断言。它应该只是此地图中的一个条目。

尝试这样的事情:

- Foo: {}
- Bar:
  b1: 15