使用boost迭代xml文件

Posted

技术标签:

【中文标题】使用boost迭代xml文件【英文标题】:Iterating on xml file with boost 【发布时间】:2016-08-30 09:02:25 【问题描述】:

我是 boost 和 xml 的新手,我正在尝试扫描一个 xml 文件并保存一些特定的值。

我阅读了this 的文章,我的问题是:如果xml 包含多个<sked>,我如何迭代它们?

也许

BOOST_FOREACH ()
   BOOST_FOREACH () // nested loop   

让我们说给定的 xml 文件如下(目的是保存 both ID):

<?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>

【问题讨论】:

看看akrzemi1.wordpress.com/2011/07/13/parsing-xml-with-boost 我可以建议使用 XML 库来解析 XML 吗? Boost 没有 XML 库。虽然它有一个属性树库 【参考方案1】:

从我的这个较早的答案 (boost::ptree find? or how to access deep arrays? C++) 中汲取灵感,编写一个函数来访问树节点:

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;

现在您可以简单地读取文件:

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";

哪些打印:

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
------------------------------

在线完整演示

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";
    

【讨论】:

以上是关于使用boost迭代xml文件的主要内容,如果未能解决你的问题,请参考以下文章

Boost Property ptree:boost write_xml 在 xml 文件的子元素中添加 unicode 0x0 字符

如何使用 ptree(boost) 遍历 XML 文件中的同名子级?

使用 Boost 的属性树添加 XML 标头 [重复]

Boost属性树xml解析No such node()

如何使用 boost::property_tree 重置 xml 元素的属性?

c ++如何使用boost xml解析器读取XML并存储在地图中