2

I have following xml data and i want to parse through boost xml parser.

<?xml version="1.0" encoding="UTF-8"?>
<applications>
    <application>
            <id>1</id>
            <platform>linux-x64</platform>
            <version>2.4</version>
    </application>
    <application>
            <id>2</id>
            <platform>windows</platform>
            <version>2.5</version>
    </application>
    <application>
            <id>3</id>
            <platform>linux</platform>
            <version>2.6</version>
    </application>
</applications>

I have written below boost code but I read only first child of "applications" and not able to read other two childs. Everytime inner loop get the data of first child.

boost::property_tree::ptree pt;
boost::property_tree::read_xml(sModel, pt); // sModel is filename which contains above xml data

BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child("applications"))
{
    std::string key = v.first.data();       
    std::string Id, platform, version;

    if (key == std::string("application"))
    {
        BOOST_FOREACH(boost::property_tree::ptree::value_type &v_, pt.get_child("applications.application"))
        {
            std::string app_key = v_.first.data();
            std::string app_value = v_.second.data();

            if (app_key == std::string("id"))
                pkgId = app_value;
            else if (app_key == std::string("platform"))
                platform = app_value;
            else if (app_key == std::string("version"))
                version = app_value;
        }
    }
}

Here, every time i get the platform as "linux-x64". Can someone guide how to read all the child through this boost xml ?

Thanks in Advance.

Neel
  • 451
  • 1
  • 9
  • 23
  • 1
    There isn't really a Boost XML parser. PropertyTree has some rudimentary support for loading from XML through a modified RapidXML parser, but it doesn't support most of XML, and as you can see, is a bit iffy when it comes to accessing the data. – Sebastian Redl Nov 30 '17 at 08:57
  • @SebastianRedl thank you for spreading the gospel. I'm glad it's becoming common knowledge. I wouldn't say data access is iffy; in fact it's pretty nice for property access. (see e.g. [avoiding loop frenzy](https://stackoverflow.com/questions/47013164/boostproperty-tree-parsing-of-complex-xml-strucure/47019176#47019176) and [translators](https://stackoverflow.com/a/43769414/85371)). – sehe Nov 30 '17 at 13:08

2 Answers2

3

get_child (and all the other path-based access functions) isn't very good at dealing with multiple identical keys. It will choose the first child with the given key and return that, ignoring all others.

But you don't need get_child, because you already hold the node you want in your hand.

pt.get_child("applications") gives you a ptree. Iterating over that gives you a ptree::value_type, which is a std::pair<std::string, ptree>.

The first weird thing, then, is this line:

std::string key = v.first.data();

The data() function you're calling here is std::string::data, not ptree::data. You could just write

std::string key = v.first;

The next strange thing is the comparison:

if (key == std::string("application"))

You don't need to explicitly construct a std::string here. In fact, doing so is a pessimization, because it has to allocate a string buffer and copy the string there, when std::string has comparison operators for C-style strings.

Then you iterator over pt.get_child("applications.application"), but you don't need to do this lookup - v.second is already the tree you want.

Furthermore, you don't need to iterate over the child at all, you can use its lookup functions to get what you need.

std::string pkgId = v.second.get("id", "");

So to sum up, this is the code I would write:

boost::property_tree::ptree pt;
boost::property_tree::read_xml(sModel, pt);

BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child("applications"))
{
    // You can even omit this check if you can rely on all children
    // being application nodes.
    if (v.first == "application")
    {
        std::string pkgId = v.second.get("id", "");
        std::string platform = v.second.get("platform", "");
        std::string version = v.second.get("version", "");
    }
}
Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • Thank you Sebastian for your detail reply. I have tried the sum up code you provided but everytime it prints "id: 1". platform: linux-x64 and version : 2.4. Any idea ? – Neel Nov 30 '17 at 09:45
  • Does it at least print it three times? I don't have a computer with Boost available at the moment so I can't debug my code. – Sebastian Redl Nov 30 '17 at 10:04
  • Yes. it prints three times. – Neel Nov 30 '17 at 10:07
  • Yes. Working fine. My fault in reading file. Thank you so much for your reply. – Neel Nov 30 '17 at 10:58
0

Check this example:

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

struct Application
{
    int          m_id
    std::string  m_platform;
    float        m_version;
};

typedef std::vector<Application> AppList;

AppList Read()
{
    using boost::property_tree::ptree;

    // Populate tree structure (pt):

    ptree pt;
    read_xml("applications.xml", pt); // For example.

    // Traverse pt:

    AppList List;
    BOOST_FOREACH(ptree::value_type const& v, pt.get_child("applications"))
    {
        if (v.first == "application")
        {
            Application App;
            App.id = v.second.get<int>("id");
            App.platform = v.second.get<std::string>("platform");
            App.version = v.second.get<float>("version");

            List.push_back(App);
        }
    }

    return List;
}
Amit G.
  • 2,546
  • 2
  • 22
  • 30
  • Generally, answers are much more helpful if they include an explanation of what the code is intended to do, and why that solves the problem without introducing others. – Tim Diekmann Jun 02 '18 at 00:40
  • The request at the top of the page is: "I have following xml data and i want to parse through boost xml parser". So, the code intends to parse the given XML file, to list the "applications" (for each application: id, platform, & version), & to return the list. – Amit G. Jun 02 '18 at 00:59