C++. Сборник рецептов
Шрифт:
Несколько важных особенностей SAX2 не проиллюстрировано в примерах 14.6, 14.7 и 14.8. Например, класс
SAX2XMLReader
содержит перегрузку метода parse
, которая принимает в качестве аргумента экземпляр xercesc::InputSource
вместо строки в С-стиле. InputSource
является абстрактным классом, инкапсулирующим источник символьных данных; конкретные его подклассы, в том числе xercesc::MemBufInputSource
и xercesc::URLInputSource
, позволяют парсеру SAX2 анализировать документ XML, который находится не в локальной файловой системе. Более
ContentHandler
содержит много дополнительных методов, например startDocument
и endDocument
, которые сигнализируют о начале и конце документа XML, и setLocator
, который позволяет задать объект Locator
, отслеживающий текущую позицию анализируемого файла. Существуют также другие интерфейсы обработчиков, включая DTDHandler
и EntityResolver
(соответствующие базовой спецификации SAX 2.0), а также DeclarationHandler
и LexicalHandler
(соответствующие стандартизованным расширениям SAX 2.0). Кроме того, можно в одном классе реализовать несколько интерфейсов обработчиков. Это можно легко сделать в классе
xercesc::DefaultHandler
, потому что он является производным от всех интерфейсов обработчиков и содержит реализации своих виртуальных функций, в которых не выполняется никаких действий. Следовательно, я мог бы добавить методы из CircusErrorHandler
в CircusContentHandler
и следующим образом модифицировать пример 14.8. // Зарегистрировать обработчики
CircusContentHandler handler(animalList);
parser->setContentHandler(&handler);
parser->setErrorHandler(&handler);
Пример 14.8 имеет еще одну, последнюю особенность, которую вы должны были заметить: обработчик
CircusContentHandler
не проверяет корректность структуры экземпляра анализируемого документа, т.е. не убеждается в том, что корневым является элемент animalList
или что все дочерние элементы корня являются элементами animal
. Это сильно отличается от примера 14.3. Например, функция main
из примера 14.3 проверяет то, что элементом верхнего уровня является animalList
, а функция nodeToAnimal
проверяет то, что ее аргументы представляют элемент animal
, содержащий точно пять дочерних элементов типа name
, species
, dateOfBirth
, veterinarian
и trainer
. Пример 14.6 можно модифицировать, чтобы он выполнял подобного рода проверки. Например, обработчик
ContentHandler
в примере 14.9 удостоверяется в том, что корневым элементом документа является animalList
и что его дочерние элементы имеют тип animal
, а дочерние элементы элемента animal
не содержат других элементов. Это можно сделать с помощью трех флагов типа boolean
, parsingAnimalList_
, parsingAnimal_
и parsingAnimalChild_
, которые регистрируют анализируемую в данный момент область документа. Методы startElement
и endElement
startAnimalChild
и endElementChild
, реализация которых очень напоминает реализацию методов startElement
и endElement
из примера 14.6. Пример 14.9. Обработчик SAX2 ContentHandler документа animals.xml, который проверяет структуру документа
// Реализует функции обратного вызова, которые получают символьные данные и
// уведомляют о начале и конце элементов
class CircusContentHandler : public DefaultHandler {
public:
CircusContentHandler(vector<Animal>& animalList)
: animalList_(animalList), // заполняемый список
parsingAnimalList_(false), // состояние анализа
parsingAnimal_(false), // состояние анализа
parsingAnimalChild_(false) // состояние анализа
{}
// Получает уведомления от парсера при каждой встрече начала
// какого-нибудь элемента
void startElement(
const XMLCh *const uri, // uri пространства имен
const XMLCh *const localname, // простое имя тега
const XMLCh *const qname, // квалифицированное имя тега
const Attributes &attrs) // Набор атрибутов
{
static XercesString animalList = fromNative("animalList");
static XercesString animal = fromNative("animal");
static XercesString xmlns =
fromNative("http://www.feldman-family-circus.com");
// Проверяет uri пространства имен
if (uri != xmlns)
throw runtime_error(
string("wrong namespace uri: ") + toNative(uri)
);
// (i) Обновить флаги parsingAnimalList_, parsingAnimal_
// и parsingAnimalChild_, которые показывают, в какой части
// документа мы находимся
// (ii) Убедиться, что элементы имеют правильную вложенность
//
// (iii) Делегировать основную работу методу
// startAnimalChild
if (!parsingAnimalList_) {
// Мы только что встретили корень документа
if (localname == animalList) {
parsingAnimalList_ = true; // Обновить состояние анализа.
} else {
// Неправильная вложенность
throw runtime_error(
string("expected 'animalList', got ") + toNative(localname)
Поделиться:
Популярные книги
Весь цикл «Десантник на престоле». Шесть книг
Десантник на престоле
Фантастика:
альтернативная история
8.38
рейтинг книги
Убивать чтобы жить 6
6. УЧЖ
Фантастика:
боевая фантастика
космическая фантастика
рпг
5.00
рейтинг книги
Мужчина моей судьбы
2. Мужчина не моей мечты
Любовные романы:
любовно-фантастические романы
8.03
рейтинг книги
Прорвемся, опера! Книга 3
3. Опер
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Бастард Императора. Том 2
2. Бастард Императора
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Измена. Право на сына
4. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Игра на чужом поле
14. Девяностые
Фантастика:
попаданцы
альтернативная история
5.50
рейтинг книги
Жена со скидкой, или Случайный брак
Любовные романы:
любовно-фантастические романы
8.15
рейтинг книги
Ворон. Осколки нас
2. Ворон
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Сумеречный стрелок
1. Сумеречный стрелок
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Измена. Испорченная свадьба
Любовные романы:
современные любовные романы
короткие любовные романы
5.00
рейтинг книги
Прометей: Неандерталец
4. Прометей
Фантастика:
героическая фантастика
альтернативная история
7.88
рейтинг книги
Генерал-адмирал. Тетралогия
Генерал-адмирал
Фантастика:
альтернативная история
8.71
рейтинг книги
Четвертый год
3. Пограничная река
Фантастика:
фэнтези
9.22