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

时间:2016-02-10 11:38:54

标签: c++ xml boost

作为示例,我使用此处列出的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国家的子节点。如何阅读直到标记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 <string, string>中阅读并存储如下内容。

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

1 个答案:

答案 0 :(得分:0)

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

属性树是/已经/“结构化地图”:

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);
}