1

I am using Boost C++ property tree library (https://www.boost.org/doc/libs/1_70_0/doc/html/property_tree.html) to read and serialize some simple XML.

First I build a property tree from an XML document - that works fine.

However, I haven't been able to get a reference to a child node (let's say "b1" as in the example below) and then serialize the entire subtree whose root is "b1", including "b1", as a new XML document.

I have tried using get_child, but this will only serialize the children of the root node of my subtree (maybe to be expected based on its name).

#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;
*/
}

What I get at 1 is (my formatting, write_xml puts all on one line)

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

What I would like to get at 2 is the following xml, where "b1" is the root of the new subtree

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

Here's what I get when I call get_child("a.b1") to get the new subtree starting at "b1" (original formatting this time):

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

which is not even well formed XML.

UPDATE Just for testing, I added a couple more elements at root level of the original tree. Here's the new code:

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;;
}

and output:

<?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/>

This is obviously not well-formed XML, and doesn't directly help me, but it shows that the library is consistent however when dealing with trees at any level.

UPDATE I modified the title to correctly reflect what I'm actually trying to do - I'm not just trying to get a subtree, but serialize it to XML. The problem I'm having is that using just the documented class methods, while I can get a subtree, serialization traverses the root node, its children (which is what I want) but its peer nodes as well (which is undesired).

Ady
  • 181
  • 7

1 Answers1

0

Prelude

The library is only incosistent in how it maps to different serialization back-ends. The limitations are pretty explicitly called out in the (very terse) documentation.

It's surprising though.

Exposition

Simplifying your sample:

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

Prints

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

Getting the subtree

This part is simple:

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

Option 1

To get it to print "correctly" add a pro-forma top-level node:

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

Prints

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

Option 2

If you think that's annoying/wasteful, you could use an undocumented internal function to write the individual element instead:

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

Prints

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

Live Demo

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);
    }
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Let me make doubly sure I repeat this AGAIN: "_[Boost Property Tree is NOT an XML library](https://stackoverflow.com/a/51918373/85371)_". See also https://stackoverflow.com/a/28041081/85371, https://stackoverflow.com/questions/37188774/xml-version-and-encoding-from-boost-ptree#comment61932139_37191115, https://stackoverflow.com/a/35061106/85371, https://stackoverflow.com/a/29364109/85371, https://stackoverflow.com/questions/41609939/boost-ptree-array-of-numbers/41614072#41614072, https://stackoverflow.com/a/49470797/85371, – sehe May 05 '19 at 20:04
  • And too many ohers. Even found a reasonable duplicate that shows how to use a "proper" (well, almost) XML library instead. – sehe May 05 '19 at 20:06