c++ - 通过 boost 属性树发出 YAML 迭代(递归)

标签 c++ boost boost-propertytree yaml-cpp

我有一个小但复杂的树结构。使用 boost 属性树作为容器,我尝试迭代该树,然后使用 yaml-cpp 将其发送到 yaml 文件。图书馆。

例如,我有一个小的嵌套属性树:

fibonacci:
  type: series
  entities:
    golden_ratio:
      ratio: 2.3
    function:
      power_series: 2

我希望我的 yaml 文件看起来像这样。

我编写了一个递归函数来迭代树并发送到 yaml。

//Member variable
YAML::Emitter m_out

void iterator(const boost::property_tree::ptree& tree, const std::string& key)
{
    for (const auto& item: tree)
    {
        if (item.second.data().empty()) //check if map node
        {
            m_out << YAML::BeginMap;
            m_out << YAML::Key << item.first;
        }
        else if (!item.second.data().empty()) //else it is key/value pair
        {
            m_out << YAML::Key << item.first;
            m_out << YAML::Value << item.second.data();
        }
        if (!item.second.empty()) //If the node has child
        {
            iterator(item.second, item.first);
        }
    }
}

我使用空键调用该函数作为iterator(root, "")。我知道属性树作为键/值对工作,而 Yaml-cpp 有节点指定。在代码中,我只是尝试根据值假设树节点的类型(无值 - 映射节点,否则 - 键/值节点)

显然,我发出的 yaml 文件不具备上面所示的所需树结构,因为我的逻辑是错误的。我想创建一个递归函数,它可以迭代任何类型的树并将其发送到 yaml 文件。 是否可以迭代树并随后递归地发送到 yaml?如果是的话,我会很感激一些想法。

最佳答案

所以我采用了您想要的 YAML 并将其通过 online converter获得“可靠”的 ptree 表示(有趣的是,您将其排除在问题之外)。

然后我继续进行简单的 ptree 往返以进行健全性检查:

Live On Coliru

#include <boost/property_tree/json_parser.hpp>
#include <iostream>
using boost::property_tree::ptree;

std::istringstream sample_json();
ptree sample_ptree();

int main() {
    write_json(std::cout, sample_ptree());
}

std::istringstream sample_json() {
    return std::istringstream(R"({
        "fibonacci": {
            "type": "series",
            "entities": {
                "golden_ratio": {
                    "ratio": 2.3
                },
                "function": {
                    "power_series": 2
                }
            }
        }
    })");
}

ptree sample_ptree() {
    ptree pt;
    {
        auto stream = sample_json();
        read_json(stream, pt);
    }
    return pt;
}

打印

{
    "fibonacci": {
        "type": "series",
        "entities": {
            "golden_ratio": {
                "ratio": "2.3"
            },
            "function": {
                "power_series": "2"
            }
        }
    }
}

to_yaml采取#1

最简单的当然是读取相同的 JSON,并让 yaml-cpp进行转换:

auto stream = sample_json();
std::cout << YAML::Load(stream) << "\n";

打印:

{fibonacci: {type: series, entities: {golden_ratio: {ratio: 2.3}, function: {power_series: 2}}}}

to_yaml采取#2:漂亮的打印

首先

  • 命名很重要。 iterator没有描述该功能,并且与 well-known concept from the standard library 冲突
  • key参数未使用
  • 你只有BeginMap ,如果你没有EndMap,你怎么期待一棵有效的树呢?代码中的任何位置?
  • 请勿使用全局变量。它们使您的代码变得脆弱(非确定性、非幂等、不可重入、非线程安全等)。只需通过Emitter&作为参数。

我会让它变得更简单:

void to_yaml(ptree const& node, YAML::Emitter &m_out) {
    if (node.empty()) {
        m_out << YAML::Value << node.data(); 
    } else {
        m_out << YAML::BeginMap;
        for (auto const&item : node) {
            m_out << YAML::Key << item.first;
            to_yaml(item.second, m_out);
        }
        m_out << YAML::EndMap;
    }
}

现在,为了有一个方便的入口点,添加一个重载:

std::string to_yaml(ptree const& tree) {
    YAML::Emitter out;
    to_yaml(tree, out);
    return out.c_str();
}

现在您可以通过执行以下操作来打印结果:

std::cout << to_yaml(sample_ptree()) << "\n";

打印:

fibonacci:
  type: series
  entities:
    golden_ratio:
      ratio: 2.3
    function:
      power_series: 2

完整列表

#include <iostream>

#include <boost/property_tree/json_parser.hpp>
using boost::property_tree::ptree;

std::istringstream sample_json();
ptree sample_ptree();

#include "yaml-cpp/yaml.h"

void to_yaml(ptree const& node, YAML::Emitter &m_out) {
    if (node.empty()) {
        m_out << YAML::Value << node.data(); 
    } else {
        m_out << YAML::BeginMap;
        for (auto const&item : node) {
            m_out << YAML::Key << item.first;
            to_yaml(item.second, m_out);
        }
        m_out << YAML::EndMap;
    }
}

std::string to_yaml(ptree const& tree) {
    YAML::Emitter out;
    to_yaml(tree, out);
    return out.c_str();
}

int main() {
    write_json(std::cout, sample_ptree());

    {
        auto stream = sample_json();
        std::cout << YAML::Load(stream) << "\n";
    }

    std::cout << to_yaml(sample_ptree()) << "\n";
}

std::istringstream sample_json() {
    return std::istringstream(R"({
        "fibonacci": {
            "type": "series",
            "entities": {
                "golden_ratio": {
                    "ratio": 2.3
                },
                "function": {
                    "power_series": 2
                }
            }
        }
    })");
}

ptree sample_ptree() {
    ptree pt;
    {
        auto stream = sample_json();
        read_json(stream, pt);
    }
    return pt;
}

关于c++ - 通过 boost 属性树发出 YAML 迭代(递归),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49922112/

相关文章:

c++ - 如何从 vector 中弹出共享指针并转换为 unique_ptr

c++ - 删除后哪些指针悬空?

c++ - 迭代 std::map 的更好方法

c++ - 正确使用 boost::wait boost::condition

c++ - Boost Log 在尝试第一个日志语句时导致崩溃(当不是管理员时)

c++ - 如何处理打开和关闭 boost iostreams 设备?

c++ - 使用 Boost C++ 解析 XML 文件

c++ - 使用 boost::regex 更改文件中数据的格式

json - 如何将 boost 属性树输出为 JSON 编码字符串?

c++ - 转换为 Unicode 时提升属性树问题