Д. Стефенс - C++. Сборник рецептов
- Название:C++. Сборник рецептов
- Автор:
- Жанр:
- Издательство:КУДИЦ-ПРЕСС
- Год:2007
- Город:Москва
- ISBN:5-91136-030-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Д. Стефенс - C++. Сборник рецептов краткое содержание
Данная книга написана экспертами по C++ и содержит готовые рецепты решения каждодневных задач для программистов на С++. Один из авторов является создателем библиотеки Boost Iostreams и нескольких других библиотек C++ с открытым исходным кодом. В книге затрагивается множество тем, вот лишь некоторые из них: работа с датой и временем; потоковый ввод/вывод; обработка исключений; работа с классами и объектами; сборка приложений; синтаксический анализ XML-документов; программирование математических задач. Читатель сможет использовать готовые решения, а сэкономленное время и усилия направить на решение конкретных задач.
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()
просто обновляют эти флаги и проверяют их согласованность, делегируя задачу обновления текущего объекта Animal вспомогательным методам startAnimalChild()
и endElementChild()
, реализация которых очень напоминает реализацию методов startElement()
и endElement()
из примера 14.6.
Пример 14.9. Обработчик SAX2 ContentHandler документа animals.xml, который проверяет структуру документа
// Реализует функции обратного вызова, которые получают символьные данные и
// уведомляют о начале и конце элементов
class CircusContentHandler : public DefaultHandler {
public:
CircusContentHandler(vector& 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)
);
}
} else if (!parsingAnimal_) {
// Мы только что встретили новое животное
if (localname == animal) {
parsingAnimal_ = true; // Обновить состояние
// анализа.
animalList_.push_back(Animal()); // Добавить в список объект
// Animal.
} else {
// Неправильная вложенность
throw runtime error(
string("expected 'animal', got ") + toNative(localname)
);
}
} else {
// Вы находимся в середине анализа элемента, описывающего
// животного.
if (parsingAnimalChild_) {
// Неправильная вложенность
throw runtime_error("bad animal element");
}
// Обновить состояние анализа
parsingAnimalChild_ = true;
// Пусть startAnimalChild() выполнит реальную работу
startAnimalChild(uri, localname, qname, attrs);
}
}
void endElement(
const XMLCh *const uri, // uri пространства имен
const XMLCh *const localname, // простое имя тега
const XMLCh *const qname ) // квалифицированное имя тега
{
static XercesString animalList = fromNative("animal-list");
static XercesString animal = fromNative("animal");
// Обновить флаги parsingAnimalList, parsingAnimal_
// и parsingAnimalChild_; делегировать основную работу
// endAnimalChild()
if (localname == animal) {
parsingAnimal_ = false;
} else if (localname == animalList) {
parsingAnimalList_ = false;
} else {
endAnimalChild(uri, localname, qname);
parsingAnimalChild_ = false;
}
}
// Получает уведомления о встрече символьных данных
void characters(const XMLCh* const chars, const unsigned int length) {
// Добавляет символы в конец currentText_ для обработки методом
// endAnimalChild()
currentText.append(chars, length);
}
private:
// Если текущий элемент представляет ветеринара или дрессировщика,
// используйте attrs для конструирования объекта Contact для
// текущего Animal; в противном случае очистите currentText_,
Интервал:
Закладка: