1

In the code below iam trying to traverse through a deeply nested map and i am not sure how property tree is interpreting the data.

It is actually printing all the parent tree data and then starts printing child tree

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

#include <boost/archive/xml_oarchive.hpp>
#include <string>
#include <iostream>
#include <map>
#include <map>
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <iterator>
    using namespace boost::property_tree;
struct values
{
    std::string a;
    std::string b;
    values():a("milepost"),b("dummyval"){};
    values( std::string ab, std::string bc)
    {
        a=ab;
        b=bc;

    };

    bool operator<(const values& other) const {
         return (a< other.a && b < other.b) ;
         }
    friend std::ostream& operator<<(std::ostream& os, const values& val);

};
std::ostream& operator<< (std::ostream& os , const values& val)
{
  os << val.a <<"\t"<< val.b;
  return os;

}
int main(int argc, const char * argv[]) {

    ptree pt;
    auto& list = pt.add_child("list", ptree{});
    auto& assetlist = pt.add_child("assetlist", ptree{});
    //Create set of types firstly
    std::set<std::string> types ;
    types.insert("et");
    types.insert("pt");

    typedef std::map< int,std::set<std::string> > myGroupsMap;
    typedef std::map<std::string,values>  myWsData;
    typedef std::map< std::string , std::set<myWsData> > myFinalData;
    typedef std::map< int,std::set<myFinalData> > myGroupData;

    myGroupsMap groupTypeMap;

    groupTypeMap.insert(std::make_pair(1, types) );


    groupTypeMap.insert(std::make_pair(2, types) );
    groupTypeMap.insert(std::make_pair(3, types) );
    groupTypeMap.insert(std::make_pair(4, types) );
    groupTypeMap.insert(std::make_pair(5, types) );

    //Create the object of structure
    values a,b,c;

    //Create map and insert the string and its corresponding structure
    myWsData et_Data1,pt_Data2;
    et_Data1.insert(std::make_pair("780256", a));
    et_Data1.insert(std::make_pair("780255", b));
    et_Data1.insert(std::make_pair("780254", c));

    pt_Data2.insert(std::make_pair("780256", a));
    pt_Data2.insert(std::make_pair("780255", b));
    pt_Data2.insert(std::make_pair("780254", c));

    std::set<myWsData> myet_pt_data;
    myet_pt_data.insert(et_Data1);
    myet_pt_data.insert(pt_Data2);

    myFinalData fd , fd1 , fd2 ;
    fd.insert(std::make_pair ("ET",myet_pt_data) );
    fd.insert(std::make_pair ("PT",myet_pt_data) );

    fd1.insert(std::make_pair ("ET",myet_pt_data) );
    fd1.insert(std::make_pair ("PT",myet_pt_data) );

    fd2.insert(std::make_pair ("ET",myet_pt_data) );
    fd2.insert(std::make_pair ("PT",myet_pt_data) );

    std::set<myFinalData> mfd;
    mfd.insert(fd);
    mfd.insert(fd1);
    mfd.insert(fd2);



    myGroupData mygd;
    mygd.insert(std::make_pair (1,mfd) );
    mygd.insert(std::make_pair (2,mfd) );
    mygd.insert(std::make_pair (3,mfd) );

  for (auto &a : mygd)
   {
       for(auto &b:a.second)  //Get the std::set
       {
            for(auto &the_map:b) //get map from set
            {

                list.add("GroupId", a.first);

                list.add("GroupType",the_map.first);
                for(auto &the_set:the_map.second)
                {
                    // the_map takes all values from the set
                    // the_map actual type is std::map<std::string,values>&
                    for (const auto& the_map : the_set)
                    {
       // the_value takes all value of the current map (the_map)
       // the_value actual type is std::pair<std::string,values>&
                            assetlist.add("AssetId",the_map.first);

                            assetlist.add("Milepost",the_map.second.a);
                            assetlist.add("Dummy",the_map.second.b);

                            // list.add("value", map.first)

              //  .add("<xmlattr>.active", true);
                     }
                }
            }
        }
    }


    xml_parser::write_xml(std::cout, pt);

    return 0;
}

Output(Excerpt):

<?xml version="1.0" encoding="utf-8"?>
<list>
<GroupId>1</GroupId>
<GroupType>ET</GroupType>
<GroupType>PT</GroupType>
<GroupId>2</GroupId>
<GroupType>ET</GroupType>
<GroupType>PT</GroupType>
<GroupId>3</GroupId>
<GroupType>ET</GroupType>
<GroupType>PT</GroupType>
</list>
<assetlist>
  <AssetId>780254</AssetId>
  <Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
  <AssetId>780255</AssetId>
  <Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
  <AssetId>780256</AssetId><Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
</assetlist>

Intended Output(Excerpt)

<GroupId>1</GroupId>
<GroupType>ET</GroupType>
<assetlist>
  <AssetId>780254</AssetId>
  <Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
  <AssetId>780255</AssetId>
  <Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
  <AssetId>780256</AssetId><Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
</assetlist>
<GroupType>PT</GroupType>
<assetlist>
  <AssetId>780254</AssetId>
  <Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
  <AssetId>780255</AssetId>
  <Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
  <AssetId>780256</AssetId><Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
</assetlist>
<GroupId>2</GroupId>
<GroupType>ET</GroupType>
<assetlist>
  <AssetId>780254</AssetId>
  <Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
  <AssetId>780255</AssetId>
  <Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
  <AssetId>780256</AssetId><Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
</assetlist>
<GroupType>PT</GroupType>
<assetlist>
  <AssetId>780254</AssetId>
  <Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
  <AssetId>780255</AssetId>
  <Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
  <AssetId>780256</AssetId><Milepost>milepost</Milepost>
  <Dummy>dummyval</Dummy>
</assetlist>

How to add it in a systematic way ? The code can be run at http://coliru.stacked-crooked.com/a/763741c78d494654

Thanks tejas

LearningCpp
  • 972
  • 12
  • 29

1 Answers1

1

Trees contain their subtrees. Printing the parent tree is printing the subtrees before closing the parent.

Both your current output and the "intended" output are invalid documents (there can only be 1 root element).

You'll need to put your data into a single tree, e.g.:

ptree pt;
auto& root = pt.add_child("root", ptree{});
auto& list = root.add_child("list", ptree{});
auto& assetlist = root.add_child("assetlist", ptree{});

Which then prints the following document:

Live On Coliru

<?xml version="1.0" encoding="utf-8"?>
<root>
  <list>
    <GroupId>1</GroupId>
    <GroupType>ET</GroupType>
    <GroupId>1</GroupId>
    <GroupType>PT</GroupType>
    <GroupId>2</GroupId>
    <GroupType>ET</GroupType>
    <GroupId>2</GroupId>
    <GroupType>PT</GroupType>
    <GroupId>3</GroupId>
    <GroupType>ET</GroupType>
    <GroupId>3</GroupId>
    <GroupType>PT</GroupType>
  </list>
  <assetlist>
    <AssetId>780254</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780255</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780256</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780254</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780255</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780256</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780254</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780255</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780256</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780254</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780255</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780256</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780254</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780255</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780256</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780254</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780255</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
    <AssetId>780256</AssetId>
    <Milepost>milepost</Milepost>
    <Dummy>dummyval</Dummy>
  </assetlist>
</root>

Which is actually well-formed XML :)

UPDATE To the comments

If you want to group asset lists with grouptypes, you .... need to write the code to do that?

Live On Coliru

ptree pt;
auto& list = pt.add_child("list", ptree{});
//Create set of types firstly
std::set<std::string> types { "et", "pt" };

typedef std::map<std::string,values>  myWsData;
typedef std::map< std::string , std::set<myWsData> > myFinalData;
typedef std::map< int,std::set<myFinalData> > myGroupData;

values a,b,c;

myWsData et_Data1 { { "780256", a }, { "780255", b }, { "780254", c } }, 
         pt_Data2 = et_Data1;

std::set<myWsData> myet_pt_data { et_Data1, pt_Data2 };

myFinalData fd , fd1 = fd, fd2 = fd;

std::set<myFinalData> mfd {
    { { "ET", myet_pt_data }, { "PT", myet_pt_data } },
    { { "ET", myet_pt_data }, { "PT", myet_pt_data } },
    { { "ET", myet_pt_data }, { "PT", myet_pt_data } } };
mfd.insert(fd);
mfd.insert(fd1);
mfd.insert(fd2);

myGroupData mygd;
mygd.insert(std::make_pair (1,mfd) );
mygd.insert(std::make_pair (2,mfd) );
mygd.insert(std::make_pair (3,mfd) );

for (auto &a : mygd)
{
    for(auto &b:a.second)  //Get the std::set
    {
        for(auto &the_map:b) //get map from set
        {
            auto& group = list.add_child("group", {});

            group.add("<xmlattr>.GroupId", a.first);
            group.add("GroupType",the_map.first);

            auto& assetlist = group.add_child("assetlist", ptree{});

            for(auto &the_set:the_map.second)
            {
                // the_map takes all values from the set
                // the_map actual type is std::map<std::string,values>&
                for (const auto& the_map : the_set)
                {
                    // the_value takes all value of the current map (the_map)
                    // the_value actual type is std::pair<std::string,values>&
                    assetlist.add("AssetId",the_map.first);

                    assetlist.add("Milepost",the_map.second.a);
                    assetlist.add("Dummy",the_map.second.b);

                    // assetlist.add("value", map.first)

                    //  .add("<xmlattr>.active", true);
                }
            }

        }
    }
}

xml_parser::write_xml(std::cout, pt);

Prints:

<?xml version="1.0" encoding="utf-8"?>
<list>
  <group GroupId="1">
    <GroupType>ET</GroupType>
    <assetlist>
      <AssetId>780254</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
      <AssetId>780255</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
      <AssetId>780256</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
    </assetlist>
  </group>
  <group GroupId="1">
    <GroupType>PT</GroupType>
    <assetlist>
      <AssetId>780254</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
      <AssetId>780255</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
      <AssetId>780256</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
    </assetlist>
  </group>
  <group GroupId="2">
    <GroupType>ET</GroupType>
    <assetlist>
      <AssetId>780254</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
      <AssetId>780255</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
      <AssetId>780256</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
    </assetlist>
  </group>
  <group GroupId="2">
    <GroupType>PT</GroupType>
    <assetlist>
      <AssetId>780254</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
      <AssetId>780255</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
      <AssetId>780256</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
    </assetlist>
  </group>
  <group GroupId="3">
    <GroupType>ET</GroupType>
    <assetlist>
      <AssetId>780254</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
      <AssetId>780255</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
      <AssetId>780256</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
    </assetlist>
  </group>
  <group GroupId="3">
    <GroupType>PT</GroupType>
    <assetlist>
      <AssetId>780254</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
      <AssetId>780255</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
      <AssetId>780256</AssetId>
      <Milepost>milepost</Milepost>
      <Dummy>dummyval</Dummy>
    </assetlist>
  </group>
</list>
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Oops , then it won't suit my requirement , each group id has a group type and it's asset list , and this is nt printing that way. Ex instead of add functions if we have cout , it prints the values exactly the way I need – LearningCpp Mar 28 '17 at 13:05
  • What? ... Maybe (a) you can make the question clearer (b) you can just write the code you know you need. – sehe Mar 28 '17 at 13:07
  • `for (auto &a : mygd) { for(auto &b:a.second) /*Get the std::set*/ { for(auto &the_map:b) /*get map from set*/` - and you expect us to magically reverse engineer your problem domain and functional requirements from that.? – sehe Mar 28 '17 at 13:10
  • Maybe you want something like this http://coliru.stacked-crooked.com/a/9160e5d0c0a18c7c - which is BOTH valid XML _and_ it groups assets by groupID. I made up some valid XML for the purpose. See **Update** in the answer. – sehe Mar 28 '17 at 13:23
  • Ohhhh , I was about to post the cout data sehe – LearningCpp Mar 28 '17 at 13:27
  • "the cout data". While you're learning C++ it's probably a good idea to start developing a much stricter technical language - this will lead to clearer mental model, and you'll be able to better understand the requirements you are facing. – sehe Mar 28 '17 at 13:31
  • Sure sehe I meant the data that gets printed to standard output using std::cout – LearningCpp Mar 28 '17 at 13:39
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/139255/discussion-between-sehe-and-learningcpp). – sehe Mar 28 '17 at 13:44