1

My question is related to : boost

Some of the boost code is working correctly to find that a node has child, but if one node have two other nodes it didn't recognize the children.

It's recursive call to be able to read all the tree nodes and then apply the copy of the value to the google protocol buffer

void ReadXML(iptree& tree, string doc)
{
    const GPF* gpf= pMessage->GetGPF();
    for(int i = 0 ; i < gpf->field_count(); ++i)
    { 
          string fieldName = GetName(i);
          boost::optional< iptree & > chl =  pt.get_child_optional(fieldName); 
          if(chl) { 
          for( auto a : *chl ){
             boost::property_tree::iptree subtree = (boost::property_tree::iptree) a.second ;
             assignDoc(doc);
                 ReadXML(subtree, doc);
             }
           }
      }     
}

the XML file

<?xml version="1.0" encoding="utf-8"?>
<nodeA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <nodeA.1>This is the Adresse</nodeA.1>
    <nodeA.2>
    <node1>
      <node1.1>
        <node1.1.1>Female</node1.1.1>
        <node1.1.2>23</node1.1.2>
        <node1.1.3>Engineer</node1.1.3>
      </node1.1>
      <node1.1>
        <node1.2.1>Female</node1.2.1>
        <node1.2.2>35</node1.2.2>
        <node1.2.3>Doctors</node1.2.3>
      </node1.1>
    </node1>
</nodeA.2>
<nodeA.3>Car 1</nodeA.3>
</nodeA>

My problem is that node1 is not recognised as having child. I don't know if it's because there are two children nodes with the same name.

Note that the XML files may change from one client to another. I may have different nodes.

Do I have to use a.second or a.first?

Community
  • 1
  • 1
melom
  • 107
  • 1
  • 13
  • why are you using a C-style cast `(boost::property_tree::iptree)` there? If you stop doing that and let the compiler do the checking, the compiler will _also_ tell you what you need to use. – sehe Nov 06 '14 at 17:52
  • I the subtree : it was the existing code I did change any on it so I don`t have to cast ? – melom Nov 06 '14 at 19:25

2 Answers2

0

Here

boost::optional< iptree & > chl =  pt.get_child_optional(fieldName);

you explicitly search for a child with a given name. This name never seems the change during recursion. On every level you look for children with the same name it seems.

Oncaphillis
  • 1,888
  • 13
  • 15
  • I modify the code to change the field name but still not seeing the child – melom Nov 06 '14 at 19:31
  • @melom So, what made it suddenly work on december 28th? – sehe Dec 28 '14 at 22:40
  • @sehe since it was a legacy code and there were a lot of function used with boost we didn't change boost to pugi, two weeks ago we implement the code with boost and it works as supposed, but we use puxi for a new project so I wanted to give a good answer for both since your solution help me on another project – melom Dec 29 '14 at 00:21
  • I don't understand. You didn't answer my question (why does it now work? since at Nov 6 you said "still not seeing the child) and you didn't "give a good answer for both". You just removed the votes for mine. I don't care about the votes, but you seem to be confused about how voting and accepting works on SO – sehe Dec 29 '14 at 00:26
0

I think you could/should be looking at this problem from a higher level.

Boost Property Tree uses RapidXML under the hood. PugiXML is a similar, but more modern library that can also be used in header-only mode. With PugiXML you could write:

pugi::xml_document doc;
doc.load(iss);

for (auto& node : doc.select_nodes("*/descendant::*[count(*)=3]/*[count(*)=0]/.."))
{
    auto values = node.node().select_nodes("*/text()");
    std::cout << "Gender    " << values[0].node().value() << "\n";
    std::cout << "Age       " << values[1].node().value() << "\n";
    std::cout << "Job Title " << values[2].node().value() << "\n";
}

It selects all descendants of the root node (nodeA) that three leaf child nodes, and interprets them as Gender, Age and Job Title. It prints:

Gender    Female
Age       23
Job Title Engineer
Gender    Female
Age       35
Job Title Doctors

I hope you will find this constructive.


Full Demo

On my system to build, simply:

sudo apt-get install libpugixml-dev
g++ -std=c++11 demo.cpp -lpugixml -o demo
./demo

demo.cpp:

#include <pugiconfig.hpp>
#define PUGIXML_HEADER_ONLY
#include <pugixml.hpp>

#include <iostream>
#include <sstream>

int main()
{
    std::istringstream iss("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
            "<nodeA xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">"
                "<nodeA.1>This is the Adresse</nodeA.1>"
                "<nodeA.2>"
                    "<node1>"
                        "<node1.1>"
                            "<node1.1.1>Female</node1.1.1>"
                            "<node1.1.2>23</node1.1.2>"
                            "<node1.1.3>Engineer</node1.1.3>"
                        "</node1.1>"
                        "<node1.2>"
                            "<node1.2.1>Female</node1.2.1>"
                            "<node1.2.2>35</node1.2.2>"
                            "<node1.2.3>Doctors</node1.2.3>"
                        "</node1.2>"
                    "</node1>"
                "</nodeA.2>"
            "<nodeA.3>Car 1</nodeA.3>"
        "</nodeA>");

    pugi::xml_document doc;
    doc.load(iss);

    for (auto& node : doc.select_nodes("*/descendant::*[count(*)=3]/*[count(*)=0]/.."))
    {
        auto values = node.node().select_nodes("*/text()");
        std::cout << "Gender    " << values[0].node().value() << "\n";
        std::cout << "Age       " << values[1].node().value() << "\n";
        std::cout << "Job Title " << values[2].node().value() << "\n";
    }

    //doc.save(std::cout);
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • thank you for your response, I`ll take a look to PugiXML, I found that I can build it and use with Visual studio, to read a file only I need is : pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("tree.xml"); I`ll give it a try, in PugiXML can I ignore a node : example start to loop from node1 instead of starting from the beginning ? – melom Nov 07 '14 at 01:40
  • You can do whatever you want. In my code I "loop" from `node` inside the loop (the second` select_nodes`). I suggest a declarative style, instead of your imperative style thinking. (Think "what should happen", not "how should it be done") – sehe Nov 07 '14 at 01:41
  • at the end I am using pugi but I had an issue passing the new pugi::xml_document pugixmlFile as augument in the function I have the error pugi::xml_document::xml_document' : cannot access private member declared in class 'pugi::xml_document is there is any work around ? thanks – melom Nov 12 '14 at 20:00
  • @melom you nneed to show more code. At this point all I can say is "don't call private functions". Did you notice xml_document is not copyable? Just pass it by reference, or use e.g. `unique_ptr` – sehe Nov 12 '14 at 20:04