【问题标题】:How to serialize a subtree of a Boost property tree to XML [duplicate]如何将Boost属性树的子树序列化为XML [重复]
【发布时间】:2019-09-22 15:33:36
【问题描述】:

我正在使用 Boost C++ 属性树库 (https://www.boost.org/doc/libs/1_70_0/doc/html/property_tree.html) 来读取和序列化一些简单的 XML。

首先我从一个 XML 文档构建一个属性树 - 效果很好。

但是,我无法获得对子节点的引用(比如下面的示例中的“b1”),然后将根为“b1”的整个子树序列化,包括“b1”,如一个新的 XML 文档。

我曾尝试使用 get_child,但这只会序列化我的子树根节点的子节点(可能根据其名称预期)。

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <iostream>

namespace pt = boost::property_tree;

void test() {
    pt::ptree tree;

    // populate tree
    tree.put("a.b1", "value1");
    tree.put("a.b2", "value2");
    tree.put("a.b1.c1", "");
    tree.put("a.b1.c2", "");
    tree.put("a.b1.c3", "");
    tree.put("a.b1.c4", "");

    std::ostringstream os;
    pt::write_xml(os, tree);

    // 1. dump tree as xml to cout
    std::cout << os.str() << std::endl;

/*
    here I would like to use some sort of get_subtree 
    function get a subtree of "tree" starting at and including 
    node "a.b1", and serialize it as XML:

    pt::tree subtree = tree.get_subtree( "a.b1" );

    std::ostringstream os1;
    pt::write_xml(os1, subtree)
    // 2. dump subtree as xml to cout
    std::cout << os1.str() << std::endl;
*/
}

我在 1 得到的是(我的格式,write_xml 全部放在一行上)

<?xml version="1.0" encoding="utf-8"?>
<a>
 <b1>value1
  <c1/>
  <c2/>
  <c3/>
  <c4/>
 </b1>
 <b2>value2
 </b2>
</a>

我想在 2 得到的是以下 xml,其中“b1”是新子树的根

<?xml version="1.0" encoding="utf-8"?>
<b1>value1
 <c1/>
 <c2/>
 <c3/>
 <c4/>
</b1>

当我调用 get_child("a.b1") 以获取从 "b1" 开始的新子树(这次是原始格式)时,我得到了以下结果:

<?xml version="1.0" encoding="utf-8"?>
b1_value<c1/><c2/><c3/><c4/>

这甚至不是格式良好的 XML。

更新 只是为了测试,我在原始树的根级别添加了更多元素。这是新代码:

void test() {
        pt::ptree tree;

        // populate tree
        tree.put("a.b1", "b1_value");
        tree.put("a.b2", "b2_value");
        tree.put("a.b1.c1", "");
        tree.put("a.b1.c2", "");
        tree.put("a.b1.c3", "");
        tree.put("a.b1.c4", "");
        tree.put("x", "");
        tree.put("x.m", "");
        tree.put("y", "");

        std::ostringstream os;
        pt::write_xml(os, tree);

        // dump tree as xml to cout
        std::cout << os.str() << std::endl;;
}

和输出:

<?xml version="1.0" encoding="utf-8"?>
<a>
 <b1>b1_value
  <c1/>
  <c2/>
  <c3/>
  <c4/>
 </b1>
 <b2>b2_value</b2>
</a>
<x>
 <m/>
</x>
<y/>

这显然不是格式良好的 XML,并且不会直接帮助我,但它表明该库在处理任何级别的树时都是一致的。

更新 我修改了标题以正确反映我实际想要做的事情——我不只是想获得一个子树,而是将它序列化为 XML。我遇到的问题是,只使用记录的类方法,虽然我可以获得一个子树,但序列化遍历根节点、它的子节点(这是我想要的),但它的对等节点也是如此(这是不希望的)。

【问题讨论】:

    标签: c++ xml boost


    【解决方案1】:

    前奏

    该库只是在映射到不同序列化后端的方式上不一致。在(非常简洁的)文档中非常明确地指出了这些限制。

    这很令人惊讶。

    博览会

    简化您的示例:

    pt::ptree tree;
    
    // populate tree
    tree.put("a.b1", "value1");
    tree.put("a.b2", "value2");
    tree.put("a.b1.c1", "");
    tree.put("a.b1.c2", "");
    tree.put("a.b1.c3", "");
    tree.put("a.b1.c4", "");
    
    auto options = pt::xml_writer_make_settings<std::string>(' ', 4);
    write_xml(std::cout, tree, options);
    

    打印

    <?xml version="1.0" encoding="utf-8"?>
    <a>
        <b1>
            value1
            <c1/>
            <c2/>
            <c3/>
            <c4/>
        </b1>
        <b2>value2</b2>
    </a>
    

    获取子树

    这部分很简单:

    pt::ptree const& subtree = tree.get_child("a.b1");
    

    选项 1

    要让它“正确”打印,请添加一个备考顶级节点:

    // option 1
    {
        pt::ptree fake_root;
        fake_root.add_child("b1", subtree);
        write_xml(std::cout, fake_root, options);
    }
    

    打印

    <?xml version="1.0" encoding="utf-8"?>
    <b1>
        value1
        <c1/>
        <c2/>
        <c3/>
        <c4/>
    </b1>
    

    选项 2

    如果您认为这很烦人/浪费,您可以使用未记录的内部函数来编写单个元素:

    // option 2
    {
        pt::xml_parser::write_xml_element(std::cout, "b1", subtree, 0, options);
    }
    

    打印

    <b1>
        value1
        <c1/>
        <c2/>
        <c3/>
        <c4/>
    </b1>
    

    现场演示

    Live On Coliru

    #include <boost/property_tree/ptree.hpp>
    #include <boost/property_tree/xml_parser.hpp>
    #include <iostream>
    
    namespace pt = boost::property_tree;
    
    int main() {
        pt::ptree tree;
    
        // populate tree
        tree.put("a.b1", "value1");
        tree.put("a.b2", "value2");
        tree.put("a.b1.c1", "");
        tree.put("a.b1.c2", "");
        tree.put("a.b1.c3", "");
        tree.put("a.b1.c4", "");
    
        auto options = pt::xml_writer_make_settings<std::string>(' ', 4);
        write_xml(std::cout, tree, options);
    
        /*
            here I would like to use some sort of get_subtree
            function get a subtree of "tree" starting at and including
            node "a.b1", and serialize it as XML:
        */
    
        pt::ptree const& subtree = tree.get_child("a.b1");
    
        // option 1
        {
            pt::ptree fake_root;
            fake_root.add_child("b1", subtree);
            write_xml(std::cout, fake_root, options);
        }
    
        // option 2
        {
            pt::xml_parser::write_xml_element(std::cout, "b1", subtree, 0, options);
        }
    }
    

    【讨论】:

    猜你喜欢
    • 2021-11-20
    • 2018-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多