使用 YAML-CPP 将 YAML 值添加到标准映射

Posted

技术标签:

【中文标题】使用 YAML-CPP 将 YAML 值添加到标准映射【英文标题】:Add YAML values to std map using YAML-CPP 【发布时间】:2018-11-07 22:07:47 【问题描述】:

我有一个 yaml 文件,其中包含嵌套地图:

SOLAR-SYSTEM:
  my/planet:
    earth: blue
  my/satellite:
    moon: white

我正在使用 yaml-cpp 来解析这些值。

有什么方法可以从 yaml 文件中提取这些值并将它们添加到 stl 映射

这让我想到了问题的第二部分。

我对 C++ 还很陌生,所以不确定地图在其中的工作原理。

在 Java 中,我使用 snakeyaml 解析相同的 yaml 文件。

它将地图添加到三重哈希图数据结构中:

HashMap<String, Map<String, Map<String, String>>>

我可以很方便地参与其中。

有什么简单的方法可以在 C++ 中做这样的事情吗?

【问题讨论】:

【参考方案1】:

我已经将这个用于 YAML 解析器的出色库使用了 2 天。所以,我也可能有一些错误。我使用 yaml-cpp ver0.6.2。

主要思想是构建自己的结构。 之后,模板特化用于特定类型的转换。

我认为您的文档结构不是很好。感觉就像嵌套 std::map 一样。我想你可以看看这个例子Only for yaml file,因为这些API都是旧的

最后,您可以将值拉入您构建的结构中。

对不起,我的英语很差。所以给你看我的代码。如果你有新的问题,你可以再问我。

另外,代码作者在这里。你可能会从他那里得到更准确的答案。

struct Planet 
    std::string earth;
;

struct Satellite 
    std::string moon;
;

struct SolarSystem 
    Planet p;
    Satellite s;
;

namespace YAML 
template<>
struct convert<Planet> 
    static Node encode(const Planet &rhs) 
        Node node;
        node["earth"] = rhs.earth;
        return node;
    

    static bool decode(const Node &node, Planet &rhs) 
        if (!node.IsMap())
            return false;
        rhs.earth = node["earth"].as<std::string>();
        return true;
    
;

template<>
struct convert<Satellite> 
    static Node encode(const Satellite &rhs) 
        Node node;
        node["moon"] = rhs.moon;
        return node;
    

    static bool decode(const Node &node, Satellite &rhs) 
        if (!node.IsMap())
            return false;
        rhs.moon = node["moon"].as<std::string>();
        return true;
    
;

template<>
struct convert<SolarSystem> 
    static Node encode(const SolarSystem &rhs) 
        Node node;
        node["my/planet"] = rhs.p;
        node["my/satellite"] = rhs.s;
        return node;
    

    static bool decode(const Node &node, SolarSystem &rhs) 
        if (!node.IsMap())
            return false;

        rhs.p = node["my/planet"].as<Planet>();
        rhs.s = node["my/satellite"].as<Satellite>();
        return true;
    
;


int main(void)

    YAML::Node doc = YAML::LoadFile("path/to/your/file");
    SolarSystem ss = doc["SOLAR-SYSTEM"].as<SolarSystem>();

    std::cout << ss.p.earth << std::endl;      // "blue"
    std::cout << ss.s.moon << std::endl;       // "white"

    return 0;

【讨论】:

欢迎来到Stack Overflow。在答案中提出问题并不合适。要么写一条评论(一旦你有足够的声誉),询问 OP 他/它正在使用哪个版本。您可以只写您的版本信息,以便清楚您使用的是什么。如果 OP 有不同的、不兼容的版本,您可能会收到一条评论说明。 @Anthon 谢谢你的建议,我的回答可能太冗长了。我会在下一个回答时简洁明了 我认为您的回答并不过分。我做了更详细的。只是限制自己的陈述。如果问题的某些方面不是 100% 清楚,请说明您所做的假设。或者做一些类似“如果你有版本 x.y,那么......如果你有版本 x.z 你有......对于旧版本我不认为......”【参考方案2】:

不知道为什么它被否决了。感谢@Crow 的回答。我不能使用它,因为它涉及对值进行硬编码。这是我设计的解决方案:

try 
        YAML::Node firstTierNode = YAML::LoadFile("config.yml");

        std::map<std::string, std::map<std::string, std::map<std::string, std::string>>> newMap1;
        for (YAML::const_iterator it = firstTierNode.begin(); it != firstTierNode.end(); ++it) 

            string level1First = it->first.as<std::string>();

            YAML::Node secondTierNode = it->second;

            std::map<std::string, std::map<std::string, std::string>>  newMap2;
            for (YAML::const_iterator it = secondTierNode.begin(); it != secondTierNode.end(); ++it) 

                string level2First = it->first.as<std::string>();

                YAML::Node thirdTierNode = it->second;

                std::map<std::string, std::string> newMap3;
                for (YAML::const_iterator it = thirdTierNode.begin(); it != thirdTierNode.end(); ++it) 

                    string level3First = it->first.as<std::string>();

                    string level3SecondString = it->second.as<std::string>();

                    newMap3.insert(std::pair<std::string, std::string>(level3First, level3SecondString));
                

                newMap2.insert(std::pair<std::string, std::map<string, string>>(level2First, newMap3));

            

            newMap1.insert(std::pair<std::string, std::map<string, std::map<string, string>>>(level1First, newMap2));

        

        for (const auto& x : newMap1) 
            std::cout <<x.first << endl << endl;
            for (const auto& y : x.second) 
                std::cout << y.first << endl << endl;
                for (const auto& z : y.second) 
                    std::cout << z.first << endl << z.second << endl << endl << endl;
                
            
        

        return 1;
    
    catch (exception& e) 
            cerr <<e.what()<< endl;
    

【讨论】:

以上是关于使用 YAML-CPP 将 YAML 值添加到标准映射的主要内容,如果未能解决你的问题,请参考以下文章

你如何防止 yaml-cpp 解析器删除所有注释?

在 yaml-cpp 中操作节点

yaml-cpp 总是创建一个大小为 0 的标量节点

yaml-cpp 不能用 g++ 编译

使用 pybind11 包装 yaml-cpp 迭代器

使用 yaml-cpp 转换为模板类