Чтение онлайн

ЖАНРЫ

C++. Сборник рецептов

Когсуэлл Джефф

Шрифт:

animal.setSpecies(toNative(currentText_));

} else if (localname == dob) {

animal.setDateOfBirth(toNative(currentText_));

}

}

 }

 // Получает уведомления, когда встречаются символьные данные

 void characters(const XMLCh* const chars,

const unsigned int length) {

// Добавить символы в конец currentText_ для обработки методом

// endElement

currentText_.append(chars, length);

 }

private:

 vector<Animal>& animalList_;

 XercesString currentText_;

};

Пример 14.7. SAX2 ErrorHandler

#include <stdexcept> // runtime_error

#include <xercesc/sax2/DefaultHandler.hpp>

//
Получает уведомления об ошибках.

class CircusErrorHandler : public DefaultHandler {

public:

 void warning(const SAXParseException& e) {

/* нет действий */

 }

 void error(const SAXParseExceptionf& e) {

throw runtime_error(toNative(e.getMessage));

 }

 void fatalError(const SAXParseException& e) { error(e); }

};

Пример 14.8. Синтаксический анализ документа animals.xml при помощи программного интерфейса SAX2

#include <exception>

#include <iostream> // cout

#include <memory> // auto_ptr

#include <vector>

#include <xercesc/sax2/SAX2XMLReader.hpp>

#include <xercesc/sax2/XMLReaderFactory.hpp>

#include <xercesc/util/PlatformUtils.hpp>

#include "animal.hpp"

#include "xerces_strings.hpp" // Пример 14.4

using namespace std;

using namespace xercesc;

// Утилита RAII инициализирует парсер и освобождает ресурсы

// при выходе из области видимости

class XercesInitializer {

public:

 XercesInitializer { XMLPlatformUtils::Initialize; }

 ~XercesInitializer { XMLPlatformUtils::Terminate; }

private:

 // Запретить копирование и присваивание

 XercesInitializer(const XercesInitializer&);

 XercesInitializer& operator=(const XercesInitializer&);

};

int main {

 try {

vector<Animal> animalList;

// Инициализировать Xerces и получить парсер

XercesInitializer init;

auto_ptr<SAX2XMLReader>

parser(XMLReaderFactory::createXMLReader);

// Зарегистрировать обработчики

CircusContentHandler content(animalList);

CircusErrorHandler error;

parser->setContentHandler(&content);

parser->setErrorHandler(&error);

//
Выполнить синтаксический анализ документа XML

parser->parse("animals.xml");

// Напечатать клички животных

for (vector<Animal>::size_type i = 0;

n = animalList.size; i < n; ++i) {

cout << animalList[i] << "\n";

}

 } catch (const SAXException& e) {

cout << "xml error: " << toNative(e.getMessage) << "\n";

return EXIT_FAILURE;

 } catch (const XMLException& e) {

cout << "xml error: " << toNative(e.getMessage) << "\n";

return EXIT_FAILURE;

 } catch (const exception& e) {

cout << e.what << "\n";

return EXIT_FAILURE;

 }

}

Обсуждение

Некоторые парсеры XML выполняют синтаксический анализ документа XML и возвращают его пользователю в виде сложного объекта С++. Именно это делает парсер TinyXml и парсер W3C DOM, который будет рассмотрен в следующем рецепте. В отличие от них парсер SAX2 использует ряд функций обратного вызова для передачи пользователю информации о документе XML по ходу его анализа. Функции обратного вызова сгруппированы в несколько интерфейсов обработчиков:

ContentHandler
получает уведомления об элементах, атрибутах и о тексте документа XML,
ErrorHandler
получает предупреждения и сообщения об ошибках, a
DTDHandler
получает уведомления о DTD документа XML.

Проектирование парсера, использующего функции обратного вызова, имеет несколько важных преимуществ. Например, можно выполнять синтаксический анализ очень больших документов, которые не помещаются в памяти. Кроме того, это может сэкономить процессорное время, потому что не надо выполнять многочисленные операции динамического выделения памяти, необходимые для конструирования узлов внутреннего представления документа XML, и потому что пользователь может создавать свое представление данных документа непосредственно, а не во время прохождения дерева документа, как я это делал в примере 14.3.

Пример 14.8 достаточно простой: я получаю парсер SAX2, регистрирую

ContentHandler
и
ErrorHandler
, анализирую документ
animals.xml
и печатаю список объектов
Animal
, заполненный обработчиком
ContentHandler
. Следует отметить два интересных момента: во-первых, функция
XMLReaderFactory::createXMLReader
возвращает экземпляр
SAX2XMLReader
, память под который выделяется динамически и должна освобождаться пользователем в явной форме; для этой цели я использую
std::auto_ptr
, чтобы обеспечить удаление парсера даже в случае возникновения исключения. Во-вторых, среда Xerces должна быть инициализирована, используя
xercesc::XMLPlatformUtils::Initialize
, и очищена при помощи
xercesc::XMLPlatformUtils::Terminate
. Я инкапсулирую эту инициализацию и очистку в классе
XercesInitializer
, который вызывает
XMLPlatformUtils::Initialize
в своем конструкторе и
XMLPlatformUtils::Terminate
в своем деструкторе. Это гарантирует вызов
Terminate
, даже если выбрасывается исключение. Это пример метода захвата ресурса при инициализации (Resource Acquisition Is Initialization — RAII), который был продемонстрирован в примере 8.3.

Поделиться с друзьями: