Iterating on xml file with boost

风格不统一 提交于 2021-02-05 06:55:27

问题


I am new with boost and xml and I am trying to scan an xml file and save some specific values.

I read this article and my question is: if the xml contains several <sked>, how do I iterate both of them?

maybe

BOOST_FOREACH ()
   BOOST_FOREACH () // nested loop   

lets say the given xml file as follow (the purpose is to save both IDs):

<?xml version="1.0"? encoding="utf-8"?>
<arrayOfSked>
 <sked>
   <ID> 1 </ID>
   <version>2</version>
   <flight>
     <carrier>BA</carrier>
     <number>4001</number>
     <precision>0.1</precision>
   </flight>
   <flight cancelled="true">
     <carrier>BA</carrier>
     <number>4002</number>
     <precision>0.2</precision>
   </flight>
 </sked>

<sked>
   <ID> 2 </ID>
   <version>2</version>
   <flight>
     <carrier>BA</carrier>
     <number>4001</number>
     <precision>0.1</precision>
   </flight>
   <flight cancelled="true">
     <carrier>BA</carrier>
     <number>4002</number>
     <precision>0.2</precision>
   </flight>
 </sked>


</arrayOfSked>

回答1:


Taking some inspiration from this older answer of mine (boost::ptree find? or how to access deep arrays? C++), write a function to visit the tree nodes:

template <typename Tree, typename Out>
Out enumerate_nodes(Tree const& pt, typename Tree::path_type path, Out out) {
    if (path.empty())
        return out;

    if (path.single()) {
        auto name = path.reduce();
        for (auto& child : pt)
        {
            if (child.first == name)
                *out++ = child.second;
        }
    } else {
        auto head = path.reduce();
        for (auto& child : pt) {
            if (head == "*" || child.first == head) {
                out = enumerate_nodes(child.second, path, out);
            }
        }
    }

    return out;
}

Now you can simply read the file:

using boost::property_tree::ptree;
ptree pt;

{
    std::ifstream ifs("input.txt");
    read_xml(ifs, pt);
}

And collect the flights:

std::vector<std::reference_wrapper<ptree const> > flights;
enumerate_nodes<ptree>(pt, "arrayOfSked.sked.flight", back_inserter(flights));

for (ptree const& flight : flights) {
    std::cout << "Canceled:\t" << (flight.get("<xmlattr>.cancelled", false)?"yes":"no") << "\n";
    std::cout << "Carrier:\t" << flight.get("carrier", "?") << "\n";
    std::cout << "Number:\t" << flight.get("number", 0) << "\n";
    std::cout << "Precision:\t" << flight.get("precision", 0.0) << "\n";
    std::cout << "------------------------------\n";
}

Which prints:

Canceled:   no
Carrier:    BA
Number: 4001
Precision:  0.1
------------------------------
Canceled:   yes
Carrier:    BA
Number: 4002
Precision:  0.2
------------------------------
Canceled:   no
Carrier:    BA
Number: 4001
Precision:  0.1
------------------------------
Canceled:   yes
Carrier:    BA
Number: 4002
Precision:  0.2
------------------------------

Full Demo Online

Live On Coliru

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

template <typename Tree, typename Out>
Out enumerate_nodes(Tree const& pt, typename Tree::path_type path, Out out) {
    if (path.empty())
        return out;

    if (path.single()) {
        auto name = path.reduce();
        for (auto& child : pt)
        {
            if (child.first == name)
                *out++ = child.second;
        }
    } else {
        auto head = path.reduce();
        for (auto& child : pt) {
            if (head == "*" || child.first == head) {
                out = enumerate_nodes(child.second, path, out);
            }
        }
    }

    return out;
}

int main() {
    using boost::property_tree::ptree;
    ptree pt;

    {
        std::ifstream ifs("input.txt");
        read_xml(ifs, pt);
    }

    std::vector<std::reference_wrapper<ptree const> > flights;
    enumerate_nodes<ptree>(pt, "arrayOfSked.sked.flight", back_inserter(flights));

    for (ptree const& flight : flights) {
        std::cout << "Canceled:\t" << (flight.get("<xmlattr>.cancelled", false)?"yes":"no") << "\n";
        std::cout << "Carrier:\t" << flight.get("carrier", "?") << "\n";
        std::cout << "Number:\t" << flight.get("number", 0) << "\n";
        std::cout << "Precision:\t" << flight.get("precision", 0.0) << "\n";
        std::cout << "------------------------------\n";
    }
}


来源:https://stackoverflow.com/questions/39223089/iterating-on-xml-file-with-boost

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!