Д. Стефенс - C++. Сборник рецептов
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_,
// подготавливая обратный вызов characters()
void startAnimalChild(
const XMLCh *const uri, // uri пространства имен
const XMLCh *const localname, // простое имя тега
const XMLCh *const qname, // квалифицированное имя тега
const Attributes &attrs ) // Набор атрибутов
{
static XercesString vet = fromNative("veterinarian");
static XercesString trainer = fromNative("trainer");
Animal& animal = animalList_.back();
if (localname == vet) {
// Мы встретили элемент "ветеринар".
animal.setVeterinarian(contactFromAttributes(attrs));
} else if (localname == trainer) {
// Мы встретили элемент "дрессировщик".
animal.setTrainer(contactFromAttributes(attrs));
} else {
// Мы встретили элемент "кличка , "вид" или
// "дата рождения". Его содержимое будет передано функцией
// обратного вызова characters().
currentText_.clear();
}
}
// Если текущий элемент представляет кличку, вид или дату рождения,
// используйте текст, находящийся в currentText_, для установки
// соответствующего свойства текущего объекта
Animal. void endAnimalChild(
const XMLCh *const uri, // uri пространства имен
const XMLCh *const localname, // простое имя тега
const XMLCh *const qname) // квалифицированное имя тега
{
static XercesString name = fromNative("name");
static XercesString species = fromNative("species");
static XercesString dob = fromNative("dateOfBirth");
// currentText_ содержит текст элемента, который только что
// закончился. Используйте его для установки свойств текущего
// объекта Animal.
Animal& animal = animalList_.back();
if (localname == name) {
animal.setName(toNative(currentText_));
} else if (localname == species) {
animal.setSpecies(toNative(currentText_));
} else if (localname == dob) {
animal.setDateOfBirth(toNative(currentText_));
}
}
vector<Animal>& animalList_; // заполняемый список
bool parsingAnimalList_; // состояние анализа
bool parsingAnimal_; // состояние анализа
bool parsingAnimalChild_; // состояние анализа
XercesString currentText_; // символьные данные текущего
// текстового узла
};
Из сравнения примера 14.9 с примером 14.6 видно, насколько сложным может быть проверка структуры документа с помощью функций обратного вызова. Более того, в примере 14.6 не делается столько проверок, как в примере 14.3: здесь, например, не проверяется порядок следования дочерних элементов элемента животного. К счастью, существует гораздо более простой способ проверки структуры документа с использованием SАХ2, как вы это увидите в рецептах 14.5 и 14.6.
Смотри такжеРецепты 14.1, 14.4, 14.5 и 14.6.
14.4. Манипулирование документом XML
ПроблемаТребуется представить документ XML в виде объекта С++, чтобы можно было манипулировать его элементами, атрибутами, текстом, DTD, инструкциями обработки и комментариями
РешениеИспользуйте реализованную в Xerces модель W3C DOM. Во-первых, используйте класс xercesc::DOMImplementationRegistry для получения экземпляра xercesc::DOMImplementation, затем используйте DOMImplementation для создания экземпляра парсера xercesc::DOMBuilder. На следующем шаге зарегистрируйте экземпляр xercesc::DOMErrorHandler для получения уведомлений об ошибках, обнаруженных в ходе анализа, и вызовите метод парсера parseURI(), передавая в качестве аргумента URI документа XML или полное имя файла. Если анализ документа завершается успешно, метод parseURI возвратит указатель на объект DOMDocument, представляющий документ XML. Затем вы можете использовать функции, определенные в спецификации W3C DOM для просмотра и манипулирования документом.
Обработав документ, вы можете сохранить его в файле, получая DOMWriter из DOMImplementation и вызывая его метод writeNode() с передачей указателя на DOMDocument в качестве аргумента.
Пример 14.10 показывает, как можно использовать DOM для синтаксического анализа документа animals.xml, приведенного в примере 14.1, затем найти и удалить узел, относящийся к слону Herby, и сохранить модифицированный документ.
Пример 14.10. Применение DOM для загрузки, модификации и затем сохранения документа XML
#include <exception>
#include <iostream> // cout
#include <xercesc/dom/DOM.hpp>
#include <xercesc/framework/LocalFileFomatTarget.hpp>
#include <xercesc/sax/SAXException.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include "animal.hpp"
#include "xerces_strings.hpp"
using namespace std;
using namespace xercesc;
/*
* Определить XercesInitializer, как это сделано в примере 14.8
*/
// Утилита RAII, которая освобождает ресурс при выходе из области видимости.
template<typename T>
class DOMPtr {
public:
DOMPtr(T* t) : t_(t) {}
~DOMPtr() { t_->release(); }
T* operator->() const { return t_; }
private:
// запретить копирование и присваивание
DOMPtr(const DOMPtr&);
DOMPtr& operator=(const DOMPtr&);
T* t_;
};
// Сообщает об ошибках, обнаруженных в ходе синтаксического анализа с
// использованием DOMBuilder.
class CircusErrorHandler : public DOMErrorHandler {
public:
bool handleFrror(const DOMError& e) {
std::cout << toNative(e.getMessage()) << "n";
return false;
}
};
// Возвращает значение элемента "name", дочернего по отношению к элементу
// "animal".
const XMLCh* getAnimalName(const DOMElement* animal) {
static XercesString name = fromNative("name");
// Просмотреть дочерние элементы объекта animal
DOMNodeList* children = animal->getChildNodes();
for (size_t i = 0, len = children->getLength(); i < Len; ++i) {
DOMNode* child = children->item(i);
if (child->getNodeType() == DOMNode::ELEMENT_NODE &&
static_cast<DOMElement*>(child)->getTagName() == name) {
// Мы нашли элемент "name".
return child->getTextContent();
}
}
return 0;
}
int main() {
try {
// Инициализировать Xerces и получить DOMImplementation;
// указать, что требуется функция загрузки и сохранения (Load and
// Save - LS)
XercesInitializer init;
DOMImplementation* impl =
DOMImplementationRegistry::getDOMImplementation(fromNative("LS").c_str()
);
if (impl == 0) {
cout << "couldn't create DOM implementationn";
Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение Д. Стефенс - C++. Сборник рецептов, относящееся к жанру Программирование. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.

