[⇐ К полному списку статей / Content] ID: 20141103_0130-loadxml

Простое чтение XML с помощью RapidXML

Я предпочитаю хранить технологическую конфигурацию моих программ и утилит в XML-файле. Пока я делал приложения с использованием Qt использовал небольшой класс, который читал эту конфигурацию и сохранял её в QStringMap.

Однако возникла потребность сделать простую утилиту на C++ но без Qt, XML-парсером которой я пользовался.
Типичный формат моего XML таков:


<?xml version="1.0" encoding="utf-8"?>
<registry>
<version>1</version>
<section id="common" >
<parameter id="locale" >ru_RU.utf8</parameter>

<parameter id="parameter1" >value1</parameter>
<parameter id="parameter2" >value2</parameter>
</section>
</registry>
Для чтения я без проблем воспользовался бесплатной библиотекой RapidXML 1.13. Сейчас она входит в Boost, но я попробовал также использовать её и отдельно (при сборке с помощью GNU C++/MinGW под Windows). Собственно библиотека эта состоит из трёх шабонных HPP-файлов, которые не требуют компиляции.

Публикую код, который читает XML и сохраняет конфигурацию в STL-коллекцию:
//#include <rapidxml.hpp>
//using namespace rapidxml;
#include <boost/property_tree/detail/rapidxml.hpp>
using namespace boost::property_tree::detail::rapidxml;

// .................

// ---
xml_document<char> doc;

//cout << "Parse..." << endl;

try
{
ifstream file( fname_xml.c_str() );
vector<char> buffer((istreambuf_iterator<char>(file)), istreambuf_iterator<char>());
buffer.push_back('\0');

doc.parse<0>( &buffer[0] );
}

catch
(parse_error e) {
cerr << "Fail. Parse error " << e.what() << endl;
return
0;
}


xml_node<> *root_node = doc.first_node();
//cout << "Root found?" << endl;

if
(root_node!=NULL)
{

//cout << "Root found!" << root_node->name() << ":" << root_node->value() << endl;
xml_node<> *node = root_node->first_node("section");
//if (node!=NULL) cout << "section found" << endl;
if (node) node = node->first_node("parameter");
//if (node!=NULL) cout << "first parameter found" << endl;
while (node!=NULL)
{

xml_attribute<>* a = node->first_attribute("id");
if
(a!=NULL)
{

config[ a->value() ] = node->value();
}


node = node->next_sibling();
}
}

cout << "========" << endl << "Check loaded configuration:" << endl;

typedef
map<string,string>::const_iterator it;
for
(it i=config.begin(); i!=config.end(); i++)
{

cout << i->first << "\t= " << i->second << endl;
}

cout << "Configuration loaded" << endl;
// ---

Стоит добавить, что когда я подставлял в doc.parse<0>( ... ) для проверки забитую в коде текстовую константу, это приводило к падению программы во время работы парсера (run-time exception). Так получалось потому, что RapidXML для скорости применяет "разрушающий" разбор - точнее в процессе работы он заменяет символы после концов символьных сущонстей XML нулевыми байтами. Таким образом они превращаются в "отдельные" строки с точки зрения C/C++ без копирования их содержимого.

Original: http://lj.rossia.org/users/shestero/142404.html
Tags: Boost, C++, RapidXML, XML, STL
[⇐ К полному списку статей / Content]


© http://netdat.ru — Bulletin Publishing System, 2011-2016.