Разбор XML-атрибутов с помощью Boost

Я хотел бы поделиться с вами проблемой, с которой я столкнулся при попытке обработать некоторые атрибуты из элементов XML в C ++ с помощью библиотек Boost (версия 1.52.0). Учитывая следующий код:

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

Допустим, у меня есть следующая структура 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>

Поэтому вывод консоли будет следующим:

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

Однако, если я решу использовать общую структуру для каждого отдельного элемента, лежащего от корневого узла (чтобы идентифицировать их по их конкретным атрибутам), результат полностью изменится. Это может быть файл 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>

И результат будет следующим:

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

Кажется, что количество элементов, висящих от корневого узла, правильно распознается, поскольку было напечатано три набора атрибутов. Тем не менее, все они относятся к атрибутам самого первого элемента …

Я не эксперт в C ++ и действительно новичок в Boost, так что это может быть что-то, что я упускаю из-за обработки хэш-карт или около того … Любой совет будет высоко ценится.

17

Решение

Проблема с вашей программой находится в этой строке:

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

С помощью этой линии вы просите ребенка pet.<xmlattr> от pets и вы делаете это 3 раза независимо от того, что f вы пересекаете Следующий Эта статья Я думаю, что вам нужно использовать это:

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

Полный код, который работает с вашими 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;
}
}
}
14

Другие решения

До сих пор, не используя эту функцию, я подозреваю, что boost::property_tree Синтаксический анализатор XML не является обычным синтаксическим анализатором XML, но ожидает определенную схему, где у вас есть ровно один определенный тег для одного конкретного свойства.

Вы можете предпочесть использовать другие анализаторы XML, которые обеспечивают разбор любой схемы XML, если вы хотите работать с XML за пределами boost::property_tree возможностей. Взгляните, например, на Xerces C ++ или же Poco XML.

2