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

Posted

技术标签:

【中文标题】c ++如何使用boost xml解析器读取XML并存储在地图中【英文标题】:c++ How to read XML using boost xml parser and store in map 【发布时间】:2016-02-10 11:38:53 【问题描述】:

作为一个例子,我使用这里列出的 XML 文件:

https://msdn.microsoft.com/en-us/library/ms256129(v=vs.110).aspx

XML 文件:

<?xml version="1.0"?>
<purchaseOrder xmlns="http://tempuri.org/po.xsd" orderDate="1999-10-20">
    <shipTo country="US">
        <name>Alice Smith</name>
        <street>123 Maple Street</street>
        <city>Mill Valley</city>
        <state>CA</state>
        <zip>90952</zip>
    </shipTo>
    <billTo country="US">
        <name>Robert Smith</name>
        <street>8 Oak Avenue</street>
        <city>Old Town</city>
        <state>PA</state>
        <zip>95819</zip>
    </billTo>
    <comment>Hurry, my lawn is going wild!</comment>
    <items>
        <item partNum="872-AA">
            <productName>Lawnmower</productName>
            <quantity>1</quantity>
            <Price>
                <USPrice>148.95</USPrice>
                <UKPrice>150.02</UKPrice>
            </Price>
            <comment>Confirm this is electric</comment>
        </item>
        <item partNum="926-AA">
            <productName>Baby Monitor</productName>
            <quantity>1</quantity>
            <Price>
                <USPrice>39.95</USPrice>
                <UKPrice>37.67</UKPrice>
            </Price>
            <USPrice>39.98</USPrice>
            <shipDate>1999-05-21</shipDate>
        </item>
    </items>
</purchaseOrder>

目前我正在使用以下代码,但使用它我只能读取一个子节点,即仅 purchaseOrder.shipTo country。如何阅读直到标签 USPrice? boost xml解析器是否支持4级标签值解析?

const std::string XML_PATH1 = "./test1.xml";
#define ROOTTAG  "purchaseOrder"
    boost::property_tree::ptree pt;
    boost::property_tree::read_xml( XML_PATH1, pt);
    BOOST_FOREACH(boost::property_tree::ptree::value_type & v, pt.get_child(ROOTTAG))
        xmlmap[v.first.data()] = v.second.data();
    

我想在xmlmap &lt;string, string&gt;中读取并存储如下。

map key = items.item partNum.USPrice
map value = 39.98 (post converting to string)

更新:

我尝试了以下方法,但它给了我编译错误

error: ‘boost::property_tree::ptree’ has no member named ‘second’
                         boost::property_tree::ptree lt = subtree.second;

代码:

const std::string XML_PATH1 = "./test1.xml";
#define ROOTTAG  "purchaseOrder"
boost::property_tree::ptree pt1;
boost::property_tree::read_xml( XML_PATH1, pt1);
BOOST_FOREACH(boost::property_tree::ptree::value_type & node, pt1.get_child(ROOTTAG))

    std::string tagname = node.first;
    tagname += ".";
    boost::property_tree::ptree subtree = node.second;
    BOOST_FOREACH( boost::property_tree::ptree::value_type & v, subtree.get_child(node.first.data()))
    
        boost::property_tree::ptree lt = subtree.second;
        tagname += v.first.data();
        tagname += ".";
        BOOST_FOREACH( boost::property_tree::ptree::value_type & vt, lt.get_child(v.first.data()))
            
                std::string name1 = vt.first.data();
                tagname += name1;
                if(name1 != "<xmlattr>") 
                    std::string tagvalue = lt.get<std::string>(name1);
                    tagname += name1;
                    xmlmap[tagname] = tagvalue;
                    
             
      

【问题讨论】:

How to iterate a boost property tree? 的可能重复项。 或者这个just iterate over elements of a ptree? 或者:“Boost 没有 XML 解析器” 【参考方案1】:

这似乎是一件非常无用的事情。

属性树是/已经/那个“结构化映射”:

auto po = pt.get_child("purchaseOrder");
std::cout << "items.item.Price.USPrice: '" << po.get("items.item.Price.USPrice", "") << "'\n";

如果您需要 XPath,请使用支持 XPath 的 XML 库 (What XML parser should I use in C++?)。

如果您想要更轻松的访问,请编写一些翻译器或访问函数。但是,无论您做什么,您都可能希望通过结构信息消除,正如您的问题所暗示的那样。

以下是我认为有用的示例:

Live On Coliru

#include <boost/property_tree/xml_parser.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
#include <map>

using Decimal = boost::multiprecision::cpp_dec_float_50;
using Tree    = boost::property_tree::ptree;

namespace BackOffice 
    struct purchaseOrder 
        struct address 
            std::string country, name, street, city, state, zip;
         shipTo, billTo;

        std::string comment;

        struct item 
            std::string partNum, productName, comment;
            size_t quantity;

            struct Price  
                Decimal USPrice, UKPrice;
             price;
        ;

        std::vector<item> items;
    ;

    void read_tree(Tree const& tree, purchaseOrder::address& into);
    void read_tree(Tree const& tree, purchaseOrder::item::Price& into);
    void read_tree(Tree const& tree, purchaseOrder::item& into);
    void read_tree(Tree const& tree, purchaseOrder& into);

    template <typename T, typename Indirect>
    void read_tree(Indirect const& maybeTree, T& into, decltype(&*maybeTree) = nullptr) 
        if (maybeTree) read_tree(*maybeTree, into); else into = ;
    

    template <typename T, typename Indirect>
    void read_tree(Indirect const& maybeTree, std::string sub, T& into, decltype(&*maybeTree) = nullptr) 
        if (maybeTree) read_tree(*maybeTree, sub, into); else into = ;
    


    template <typename T>
    void read_tree(Tree const& tree, std::string sub, std::vector<T>& into) 
        for (auto& child : tree) 
            if (child.first == sub) 
                into.emplace_back();
                read_tree(child.second, into.back());
            
        
    

    void read_tree(Tree const& tree, purchaseOrder::address& into) 
        into.country = tree.get("<xmlattr>.country", "(unknown");
        into.name    = tree.get("name",              "(unknown");
        into.street  = tree.get("street",            "(unknown");
        into.city    = tree.get("city",              "(unknown");
        into.state   = tree.get("state",             "(unknown");
        into.zip     = tree.get("zip",               "(unknown");
    

    void read_tree(Tree const& tree, purchaseOrder::item::Price& into) 
        into.UKPrice = tree.get("UKPrice", Decimal);
        into.USPrice = tree.get("USPrice", Decimal);
    

    void read_tree(Tree const& tree, purchaseOrder::item& into) 
        into.partNum     = tree.get("<xmlattr>.partNum", "(unknown");
        into.productName = tree.get("productName",       "(unknown");
        into.comment     = tree.get("comment",           "");
        read_tree(tree.get_child_optional("Price"), into.price);
    

    void read_tree(Tree const& tree, purchaseOrder& into) 
        read_tree(tree.get_child_optional("shipTo"), into.shipTo);
        read_tree(tree.get_child_optional("billTo"), into.billTo);
        read_tree(tree.get_child_optional("items"), "item", into.items);
        into.comment = tree.get("comment", "");
    



int main() 
    Tree pt;
    read_xml( "input.txt", pt);

    //auto po = pt.get_child("purchaseOrder");
    //std::cout << "items.item.Price.USPrice: '" << po.get("items.item.Price.USPrice", "") << "'\n";

    BackOffice::purchaseOrder po;
    read_tree(pt.get_child("purchaseOrder"), po);

【讨论】:

以上是关于c ++如何使用boost xml解析器读取XML并存储在地图中的主要内容,如果未能解决你的问题,请参考以下文章

使用 stax 和 dom 读取大型 XML 文件

如何从 xml 解析器中读取数据

如何从头开始创建/编写一个简单的 XML 解析器?

XML解析器

使用条件变量超时的读取器/写入器锁定

使用 XElement 解析 XML