Adding nodes with the same key to a property tree
Asked Answered
B

1

7

I am using Boost's property tree to read and write XML. Using a spreadsheet application I made I want to save the contents of the spreadsheet to xml. This is a school assignment so I am required to use the following format for the XML:

<?xml version="1.0" encoding="UTF-8"?>
<spreadsheet>
   <cell>
      <name>A2</name>
      <contents>adsf</contents>
   </cell>
   <cell>
      <name>D6</name>
      <contents>345</contents>
   </cell>
   <cell>
      <name>D2</name>
      <contents>=d6</contents>  
   </cell>
</spreadsheet>

For a simple test program I wrote:

int main(int argc, char const *argv[])
{
boost::property_tree::ptree pt;

pt.put("spreadsheet.cell.name", "a2");
pt.put("spreadsheet.cell.contents", "adsf");

write_xml("output.xml", pt);

boost::property_tree::ptree ptr;
read_xml("output.xml", ptr);

ptr.put("spreadsheet.cell.name", "d6");
ptr.put("spreadsheet.cell.contents", "345");
ptr.put("spreadsheet.cell.name", "d2");
ptr.put("spreadsheet.cell.contents", "=d6");

write_xml("output2.xml", ptr);

return 0;
}

Based on this question I see the put method replaces anything at that node, instead of adding a new one. Which is exactly the functionality I am seeing:

Output.xml

<?xml version="1.0" encoding="utf-8"?>
<spreadsheet>
  <cell>
    <name>a2</name>
    <contents>adsf</contents>
  </cell>
</spreadsheet>

Output2.xml

<?xml version="1.0" encoding="utf-8"?>
<spreadsheet>
  <cell>
    <name>d2</name>
    <contents>=d6</contents>
  </cell>
</spreadsheet>

Looking at the documentation I see this add_child method which will Add the node at the given path. Create any missing parents. If there already is a node at the path, add another one with the same key.

I can't quite figure out how to use that add_child method, could someone explain how to use it?

Is there a better way of going about this to achieve the file format I want?

Bemis answered 21/4, 2013 at 21:51 Comment(2)
Can't you just use the cell name in the child name? i.e. "spreadsheet.cell.d6"Cockloft
@k-ballo because that wouldn't meet the xml requirements.Bemis
C
16

The add_child member function allows you to insert one property_tree into the DOM of another as a child node. If the key path you provide already exists a duplicate key will be added and the child will be inserted there instead. If we change your example a little bit we can examine the results.

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

int main()
{
    // Create the first tree with two elements, name and contents
    boost::property_tree::ptree ptr1;
    ptr1.put("name", "a2");
    ptr1.put("contents", "adsf");

    // Create the a second tree with two elements, name and contents
    boost::property_tree::ptree ptr2;
    ptr2.put("name", "d6");
    ptr2.put("contents", "345");

    // Add both trees to a third and place them in node "spreadsheet.cell"
    boost::property_tree::ptree ptr3;
    ptr3.add_child("spreadsheet.cell", ptr1);
    ptr3.add_child("spreadsheet.cell", ptr2);

    boost::property_tree::write_xml("output.xml", ptr3);

    return 0;
}

When you call add_child the first time, the node for key "spreadsheet.cell" does not exist and is created. It then adds the contents of the tree (name and contents) to the newly created node. When you call add_child the second time it sees that "spreadsheet.cell" already exists but unlike put it creates a sibling node also called "cell" and inserts it at the same location.

The final output:

<?xml version="1.0" encoding="utf-8"?>
<spreadsheet>
  <cell>
    <name>a2</name>
    <contents>adsf</contents>
  </cell>
  <cell>
    <name>d6</name>
    <contents>345</contents>
  </cell>
</spreadsheet>
Curvature answered 21/4, 2013 at 22:54 Comment(4)
Awesome explanation. If I were to want to update cell d6 however, how would i navigate to that cell and change the contents in ptr3?Bemis
@Bemis Iterate over the children of spreadsheet looking for all children of type cell. Anytime you encounter one get the contents of name and if you find a match delete it. You'll need to look at the docs for specificsCurvature
nice explanation, not much documentation around add_child on net otherwise .Minter
There is also .add(name, value).Stillwell

© 2022 - 2024 — McMap. All rights reserved.