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

на главную - закладки

Жанры

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

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

Шрифт:

 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.

Давайте теперь посмотрим, как класс

CircusContentHandler
из примера 14.6 реализует интерфейс SAX2
ContentHandler
. Парсер SAX 2 вызывает метод
startElement
при каждой встрече открывающего тега элемента. Если элементу приписано пространство имен, первый аргумент,
uri
, будет содержать URI пространства имен элемента, а второй аргумент,
localname
, будет содержать ту часть имени тега элемента, которая идет за префиксом пространства имен. Если элемент не имеет пространства имен, эти два аргумента будут иметь пустые строки. Третий аргумент содержит имя тега элемента, если с элементом не связывается пространство имен; в противном случае этот аргумент может содержать либо имя тега элемента в том виде, в каком оно встречается в анализируемом документе, либо пустую строку. Четвертым аргументом является экземпляр класса
Attributes
, представляющего набор атрибутов элемента.

В приведенной в примере 14.6 реализации

startElement
я игнорирую элемент
animalList
. Когда я встречаю элемент
animal
, я добавляю новый объект
Animal
в список животных; назовем его текущим объектом
Animal
и предоставим право установки свойств этого
Animal
обработчикам других элементов. Когда я встречаю элемент
veterinarian
или
trainer
, я вызываю функцию
contactFromAttributes
для конструирования экземпляра
Contact
из набора атрибутов элемента и затем использую этот объект
Contact
для установки свойств ветеринара и дрессировщика в текущем элементе
Animal
. Когда я встречаю элемент name,
species
или
dateOfBirth
, я очищаю переменную-член
currentText_
, которая будет использоваться для хранения текстового содержимого этого элемента.

Парсер SAX2 вызывает метод

characters
для передачи символьных данных, содержащихся в элементе. Этот парсер может передавать символы элемента с помощью нескольких вызовов метода
characters
; пока не встретится закрывающий тег, нельзя быть уверенным в передаче всех символьных данных. Поэтому в реализации
characters
я просто добавляю полученные символы в конец переменной-члена
currentText_
, которую я использую для установки клички, вида и даты рождения
Animal
сразу после встречи закрывающего тега для элемента
name
,
species
или
dateOfBirth
.

Парсер SAX2 вызывает метод

endElement
при выходе из каждого элемента. Его аргументы имеют тот же смысл, который имеют первые три аргумента метода
startElement
. В реализации
endElement
, приведенной в примере 14.6, я игнорирую все элементы, отличные от
name
,
species
и
dateOfBirth
. Когда происходит обратный вызов, соответствующий одному из этих элементов, сигнализирующий о сделанном только что выходе парсера из элемента, я использую символьные данные, сохраненные в
currentText_
для установки клички, вида и даты рождения текущего объекта
Animal
.

Поделиться:
Популярные книги

Стеллар. Трибут

Прокофьев Роман Юрьевич
2. Стеллар
Фантастика:
боевая фантастика
рпг
8.75
рейтинг книги
Стеллар. Трибут

Его огонь горит для меня. Том 2

Муратова Ульяна
2. Мир Карастели
Фантастика:
юмористическая фантастика
5.40
рейтинг книги
Его огонь горит для меня. Том 2

На границе империй. Том 9. Часть 4

INDIGO
17. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 9. Часть 4

Наследник

Кулаков Алексей Иванович
1. Рюрикова кровь
Фантастика:
научная фантастика
попаданцы
альтернативная история
8.69
рейтинг книги
Наследник

Совершенно несекретно

Иванов Дмитрий
15. Девяностые
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Совершенно несекретно

Ваше Сиятельство 2

Моури Эрли
2. Ваше Сиятельство
Фантастика:
фэнтези
альтернативная история
аниме
5.00
рейтинг книги
Ваше Сиятельство 2

Прометей: каменный век II

Рави Ивар
2. Прометей
Фантастика:
альтернативная история
7.40
рейтинг книги
Прометей: каменный век II

Единственная для темного эльфа 3

Мазарин Ан
3. Мир Верея. Драконья невеста
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Единственная для темного эльфа 3

Жандарм

Семин Никита
1. Жандарм
Фантастика:
попаданцы
альтернативная история
аниме
4.11
рейтинг книги
Жандарм

Долгий путь домой

Русич Антон
Вселенная EVE Online
Фантастика:
космическая фантастика
попаданцы
6.20
рейтинг книги
Долгий путь домой

Прогрессор поневоле

Распопов Дмитрий Викторович
2. Фараон
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Прогрессор поневоле

Наследие Маозари 6

Панежин Евгений
6. Наследие Маозари
Фантастика:
попаданцы
постапокалипсис
рпг
фэнтези
эпическая фантастика
5.00
рейтинг книги
Наследие Маозари 6

Я еще не барон

Дрейк Сириус
1. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я еще не барон

Лолита

Набоков Владимир Владимирович
Проза:
классическая проза
современная проза
8.05
рейтинг книги
Лолита