1

My XML file is nested as follow:

<?xml version="1.0" encoding="utf-8"?>
<root>
<type>
<cars>
<car name="Garfield" weight="4Kg">
<spec serial_="e_54" source ="petrol" mileage="56"/>
<spec serial_="e_52" source="diesel" mileage="52"/>
<spec serial_="m_22" source="electric" mileage="51"/>
<additions source="steam" convert="153 0 1 0"/>
</car>
<car name="Awesome" weight="3Kg">
<spec serial_="t_54" source="petrol" mileage="16"/>
<spec serial_="t_52" source="wind" mileage="62"/>
<spec serial_="t_22" source="electric" mileage="81"/>
<additions source="water" convert="123 1 1 0"/>
</car>
</cars>
<planes>
<plane id="231" name ="abc">
<utilities serial_="e456" part="567"/>
</plane>
</type>
</root>

I wish to grab all "car" attributes under "cars". Furthermore, I wish to get attributes of all its child node "spec" as well.

Currently, my code is similar to one in this question: Parsing nested xml with boost

I'm able to get attributes of "car" tag. However, I'm unable to grab its attributes of its children element. Even if I'm successful in grabbing all required data for first "car", it keeps printing its children attributes same as the first node.

1 Answers1

1

Assuming you have a target structure like

struct Car {
    std::string name, weight;
    struct Spec {
        std::string serial_, source;
        double mileage;
    };
    std::vector<Spec> specs;
};

I'd write code like

for (auto& [key, node] : pt.get_child("root.type.cars")) {
    if ("car" == key) {
        Car car;
        parse(node, car);
        std::cout << car << "\n";
    }
}

Where parse is:

static bool parse(ptree const& node, Car& into)  {
    into.name   = node.get<std::string>("<xmlattr>.name");
    into.weight = node.get<std::string>("<xmlattr>.weight");
    for (auto& [name, child] : node) {
        if (name == "spec") {
            into.specs.emplace_back();
            if (!parse(child, into.specs.back())) {
                return false;
            }
        }
    }
    return true;
}

And of course, a similar overload for Spec:

static bool parse(ptree const& node, Car::Spec& into) {
    into.serial_ = node.get<std::string>("<xmlattr>.serial_");
    into.source  = node.get<std::string>("<xmlattr>.source");
    into.mileage = node.get<double>("<xmlattr>.mileage");
    return true;
}

Live Demo

#include <boost/property_tree/xml_parser.hpp>
using boost::property_tree::ptree;
#include <iostream>

struct Car {
    std::string name, weight;
    struct Spec {
        std::string serial_, source;
        double mileage;
    };
    std::vector<Spec> specs;
};

static bool parse(ptree const& node, Car::Spec& into) {
    into.serial_ = node.get<std::string>("<xmlattr>.serial_");
    into.source  = node.get<std::string>("<xmlattr>.source");
    into.mileage = node.get<double>("<xmlattr>.mileage");
    return true;
}

static bool parse(ptree const& node, Car& into)  {
    into.name   = node.get<std::string>("<xmlattr>.name");
    into.weight = node.get<std::string>("<xmlattr>.weight");
    for (auto& [name, child] : node) {
        if (name == "spec") {
            into.specs.emplace_back();
            if (!parse(child, into.specs.back())) {
                return false;
            }
        }
    }
    return true;
}

static std::ostream& operator<<(std::ostream& os, Car const& car) {
    os << "Name: " << car.name << ", Weight: " << car.weight;
    for (auto& spec : car.specs) {
        os << "\n -- [" << spec.serial_ << "; " << spec.source << "; "
           << spec.mileage << "]";
    }
    return os;
}

int main() 
{
    boost::property_tree::ptree pt;
    {
        std::ifstream ifs("input.xml");
        read_xml(ifs, pt);
    }

    for (auto& [key, node] : pt.get_child("root.type.cars")) {
        if ("car" == key) {
            Car car;
            parse(node, car);
            std::cout << car << "\n";
        }
    }
}

Prints

Name: Garfield, Weight: 4Kg
 -- [e_54; petrol; 56]
 -- [e_52; diesel; 52]
 -- [m_22; electric; 51]
Name: Awesome, Weight: 3Kg
 -- [t_54; petrol; 16]
 -- [t_52; wind; 62]
 -- [t_22; electric; 81]
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Hi @sehe, your earlier code worked great. Thanks again. However, when I added members to struct and other functions as per updated xml (i.e. "additions" tag and planes group. Its reporting a runtime error as follow: no such node as .convert. Could you help with this please – user12061536 Feb 22 '21 at 05:14
  • I can. [Posted](https://stackoverflow.com/a/66319940/85371). I hope it helps, Please consider also reading https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – sehe Feb 22 '21 at 17:16