C++ 使用 Boost 解析 XML 属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14010473/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:53:06  来源:igfitidea点击:

Parsing XML Attributes with Boost

c++xmlboostboost-propertytree

提问by grover999

I would like to share with you an issue I'm having while trying to process some attributes from XML elements in C++ with Boost libraries (version 1.52.0). Given the following code:

我想与您分享一个问题,我在尝试使用 Boost 库(1.52.0 版)处理 C++ 中 XML 元素的某些属性时遇到的问题。鉴于以下代码:

#define ATTR_SET ".<xmlattr>"
#define XML_PATH1 "./pets.xml"

#include <iostream>
#include <string>
#include <boost/foreach.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

using namespace std;
using namespace boost;
using namespace boost::property_tree;

const ptree& empty_ptree(){
    static ptree t;
    return t;
}

int main() {
    ptree tree;
    read_xml(XML_PATH1, tree);
    const ptree & formats = tree.get_child("pets", empty_ptree());
    BOOST_FOREACH(const ptree::value_type & f, formats){
        string at = f.first + ATTR_SET;
        const ptree & attributes = formats.get_child(at, empty_ptree());
        cout << "Extracting attributes from " << at << ":" << endl;
        BOOST_FOREACH(const ptree::value_type &v, attributes){
            cout << "First: " << v.first.data() << " Second: " << v.second.data() << endl;
        }
    }
}

Let's say I have the following XML structure:

假设我有以下 XML 结构:

<?xml version="1.0" encoding="utf-8"?>
<pets>
    <cat name="Garfield" weight="4Kg">
        <somestuff/>
    </cat>
    <dog name="Milu" weight="7Kg">
        <somestuff/>
    </dog>
    <bird name="Tweety" weight="0.1Kg">
        <somestuff/>
    </bird>
</pets>

Therefore, the console output I'll get will be the next:

因此,我将得到的控制台输出将是下一个:

Extracting attributes from cat.<xmlattr>:
First: name Second: Garfield
First: weight Second: 4Kg
Extracting attributes from dog.<xmlattr>:
First: name Second: Milu
First: weight Second: 7Kg
Extracting attributes from bird.<xmlattr>:
First: name Second: Tweety
First: weight Second: 0.1Kg

However, if I decide to use a common structure for every single element laying down from the root node (in order to identify them from their specific attributes), the result will completely change. This may be the XML file in such case:

但是,如果我决定为从根节点开始放置的每个元素使用通用结构(以便从它们的特定属性中识别它们),结果将完全改变。在这种情况下,这可能是 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<pets>
    <pet type="cat" name="Garfield" weight="4Kg">
        <somestuff/>
    </pet>
    <pet type="dog" name="Milu" weight="7Kg">
        <somestuff/>
    </pet>
    <pet type="bird" name="Tweety" weight="0.1Kg">
        <somestuff/>
    </pet>
</pets>

And the output would be the following:

输出如下:

Extracting attributes from pet.<xmlattr>:
First: type Second: cat
First: name Second: Garfield
First: weight Second: 4Kg
Extracting attributes from pet.<xmlattr>:
First: type Second: cat
First: name Second: Garfield
First: weight Second: 4Kg
Extracting attributes from pet.<xmlattr>:
First: type Second: cat
First: name Second: Garfield
First: weight Second: 4Kg

It seems the number of elements hanging from the root node is being properly recognized since three sets of attributes have been printed. Nevertheless, all of them refer to the attributes of the very first element...

由于打印了三组属性,因此似乎可以正确识别从根节点悬挂的元素数量。尽管如此,它们都是指第一个元素的属性......

I'm not an expert in C++ and really new to Boost, so this might be something I'm missing with respect to hash mapping processing or so... Any advice will be much appreciated.

我不是 C++ 方面的专家,而且对 Boost 真的很陌生,所以这可能是我在哈希映射处理方面所缺少的东西......任何建议将不胜感激。

采纳答案by grover999

The problem with your program is located in this line:

您程序的问题位于这一行:

const ptree & attributes = formats.get_child(at, empty_ptree());

With this line you are asking to get the child pet.<xmlattr>from petsand you do this 3 times independently of whichever fyou are traversing. Following this articleI'd guess that what you need to use is:

使用这条线,您要求pet.<xmlattr>从孩子那里得到孩子,pets并且无论f您穿过哪一条线,您都可以这样做 3 次。在这篇文章之后,我猜你需要使用的是:

const ptree & attributes = f.second.get_child("<xmlattr>", empty_ptree());

The full code, that works with both your xml files, is:

适用于您的两个 xml 文件的完整代码是:

#define ATTR_SET ".<xmlattr>"
#define XML_PATH1 "./pets.xml"

#include <iostream>
#include <string>
#include <boost/foreach.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

using namespace std;
using namespace boost;
using namespace boost::property_tree;

const ptree& empty_ptree(){
    static ptree t;
    return t;
}

int main() {
    ptree tree;
    read_xml(XML_PATH1, tree);
    const ptree & formats = tree.get_child("pets", empty_ptree());
    BOOST_FOREACH(const ptree::value_type & f, formats){
        string at = f.first + ATTR_SET;
        const ptree & attributes = f.second.get_child("<xmlattr>", empty_ptree());
        cout << "Extracting attributes from " << at << ":" << endl;
        BOOST_FOREACH(const ptree::value_type &v, attributes){
            cout << "First: " << v.first.data() << " Second: " << v.second.data() << endl;
        }
    }
}

回答by π?ντα ?ε?

Without ever using this feature so far, I would suspect that boost::property_treeXML parser isn't a common XML parser, but expects a certain schema, where you have exactly one specific tag for one specific property.

到目前为止,我还没有使用过这个特性,我怀疑boost::property_treeXML 解析器不是一个常见的 XML 解析器,而是需要一个特定的模式,在那里你有一个特定属性的特定标签。

You might prefer to use other XML parsers that provides parsing any XML schema, if you want to work with XML beyond the boost::property_treecapabilities. Have a look at e.g. Xerces C++or Poco XML.

如果您想使用超出boost::property_tree能力范围的 XML,您可能更喜欢使用其他提供解析任何 XML 模式的 XML 解析器。看看例如Xerces C++Poco XML

回答by user11507455

File to be parsed, pets.xml

要解析的文件, pets.xml

<pets>
    <pet type="cat" name="Garfield" weight="4Kg">
        <something name="test" value="*"/>
         <something name="demo" value="@"/>
    </pet>
    <pet type="dog" name="Milu" weight="7Kg">
         <something name="test1" value="$"/>
    </pet>
    <birds type="parrot">
        <bird name="african grey parrot"/>
        <bird name="amazon parrot"/>
    </birds>
</pets>

code:

代码:

// DemoPropertyTree.cpp : Defines the entry point for the console application.
//Prerequisite boost library

#include "stdafx.h"
#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/foreach.hpp>
#include<iostream>
using namespace std;
using namespace boost;
using namespace boost::property_tree;

void processPet(ptree subtree)
{
    BOOST_FOREACH(ptree::value_type petChild,subtree.get_child(""))
    {
        //processing attributes of element pet
        if(petChild.first=="<xmlattr>")
        {
            BOOST_FOREACH(ptree::value_type petAttr,petChild.second.get_child(""))
            {
                cout<<petAttr.first<<"="<<petAttr.second.data()<<endl;
            }
        }
        //processing child element of pet(something)
        else if(petChild.first=="something")
        {
            BOOST_FOREACH(ptree::value_type somethingChild,petChild.second.get_child(""))
            {
                //processing attributes of element something
                if(somethingChild.first=="<xmlattr>")
                {
                    BOOST_FOREACH(ptree::value_type somethingAttr,somethingChild.second.get_child(""))
                    {
                        cout<<somethingAttr.first<<"="<<somethingAttr.second.data()<<endl;
                    }
                }
            }
        }
    }
}
void processBirds(ptree subtree)
{
    BOOST_FOREACH(ptree::value_type birdsChild,subtree.get_child(""))
    {
        //processing attributes of element birds
        if(birdsChild.first=="<xmlattr>")
        {
            BOOST_FOREACH(ptree::value_type birdsAttr,birdsChild.second.get_child(""))
            {
                cout<<birdsAttr.first<<"="<<birdsAttr.second.data()<<endl;
            }
        }
        //processing child element of birds(bird)
        else if(birdsChild.first=="bird")
        {
            BOOST_FOREACH(ptree::value_type birdChild,birdsChild.second.get_child(""))
            {
                //processing attributes of element bird
                if(birdChild.first=="<xmlattr>")
                {
                    BOOST_FOREACH(ptree::value_type birdAttr,birdChild.second.get_child(""))
                    {
                        cout<<birdAttr.first<<"="<<birdAttr.second.data()<<endl;
                    }
                }
            }
        }
    }
}
int _tmain(int argc, _TCHAR* argv[])
{

    const std::string XML_PATH1 = "C:/Users/10871/Desktop/pets.xml";
    ptree pt1;
    boost::property_tree::read_xml( XML_PATH1, pt1  );
     cout<<"********************************************"<<endl;
    BOOST_FOREACH( ptree::value_type const& topNodeChild, pt1.get_child( "pets" ) ) 
    {
        ptree subtree = topNodeChild.second;
        if( topNodeChild.first == "pet" ) 
        {
             processPet(subtree);
             cout<<"********************************************"<<endl;
        }
        else if(topNodeChild.first=="birds")
        {
            processBirds(subtree);
             cout<<"********************************************"<<endl;
        }

    }
    getchar();
    return 0;
}

The output is shown here: output

输出如下所示: 输出