Выбрать главу

Пример 14.5. Список цирковых животных, в котором используются пространства имен XML

<?xml version="1.0" encoding="UTF-8"?>

<!- Животные цирка Feldman Family Circus с использованием пространств имен -->

<ffc:animalList xmlns:ffc="http://www.feldman-family-circus.com">

 <ffc:animal>

  <ffc:name>Herby</ffc:name>

  <ffc:species>elephant</ffc:species>

  <ffc:dateOfBirth>1992-04-23</ffc:dateOfBirth>

  <ffc:veterinarian name="Dr. Hal Brown" phone="(801)595-9627"/>

  <ffc:trainer name="Bob Fisk" phone="(801)881-2260"/>

 </ffc:animal>

 <!- и т.д. -->

</ffc:animalList>

Для анализа этого документа с помощью SAX2 определите ContentHandler, как показано в примере 14.6, и ErrorHandler, как показано в примере 14.7. Затем сконструируйте SAX2XMLReader, зарегистрируйте ваши обработчики и запустите парсер. Это проиллюстрировано в примере 14.8.

Пример 14.6. Применение SAX2 ContentHandler для синтаксического анализа документа animals.xml

#include <stdexcept> // runtime_error

#include <vector>

#include <xercesc/sax2/Attributes.hpp>

#include <xercesc/sax2/DefaultHandler.hpp> // Содержит реализации без

                                           // операций для различных

                                           // обработчиков, используемых

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

#include "animal.hpp"

using namespace std;

using namespace xercesc;

// Возвращает экземпляр Contact, построенный

// на основе заданного набора атрибутов

Contact contactFromAttributes(const Attributes &attrs) {

 // Для повышения эффективности хранить часто используемые строки

 // в статических переменных

 static XercesString name = fromNative("name");

 static XercesString phone = fromNative("phone");

 Contact result;   // Возвращаемый объект Contact.

 const XMLCh* val; // Значение атрибута name или phone.

 // Установить имя объекта Contact.

 if ((val = attrs.getValue(name.c_str())) != 0) {

  result.setName(toNative(val));

 } else {

  throw runtime_error("contact missing name attribute");

 }

 // Установить номер телефона для объекта Contact.

 if ((val = attrs.getValue(phone.c_str())) != 0) {

  result.setPhone(toNative(val));

 } else {

  throw runtime_error("contact missing phone attribute");

 }

 return result;

}

// Реализует обратные вызовы, которые получают символьные данные и

// уведомления о начале и конце элементов

class CircusContentHandler : public DefaultHandler {

public:

 CircusContentHandler(vector<Animal>& animalList) :

  animalList_(animalList) {}

 // Если текущий элемент представляет ветеринара или дрессировщика

 // используйте attrs для конструирования объекта Contact для текущего

 // Animal; в противном случае очистите currentText_, подготавливая

 // обратный вызов characters()

 void startElement(

  const XMLCh *const uri,       // URI пространства имен

  const XMLCh *const localname, // имя тега без префикса NS

  const XMLCh *const qname,     // имя тега + префикс NS

  const Attributes &attrs)      // атрибуты элементов

 {

  static XercesString animalList = fromNative("animalList");

  static XercesString animal = fromNative("animal");

  static XercesString vet = fromNative("veterinarian");

  static XercesString trainer = fromNative("trainer");

  static XercesString xmlns =

   fromNative("http://www.feldman-family-circus.com");

  // проверить URI пространства имен

  if (uri != xmlns)

   throw runtime_error(

    string("wrong namespace uri ") + toNative(uri)

   );

  if (localname == animal) {

   // Добавить в список объект Animal; это будет

   // "текущий объект Animal"

   animalList_.push_back(Animal());

  } else if (localname != animalList) {

   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 endElement(

  const XMLCh *const uri,       // URI пространства имен

  const XMLCh *const localname, // имя тега без префикса NS

  const XMLCh *const qname)     // имя тега + префикс NS

 {

  static XercesString animalList = fromNative("animal-list");

  static XercesString animal = fromNative("animal");

  static XercesString name = fromNative("name");

  static XercesString species = fromNative("species");

  static XercesString dob = fromNative("dateOfBirth");

  if (localname!= animal && localname!= animalList) {

   // currentText_ содержит текст элемента, который был

   // добавлен. Используйте его для установки свойств текущего

   // объекта Animal.

   Animal& animal = animalList_.back();

   if (localname == name) {

    animal setName(toNative(currentText_));

   } else if (localname == species) {

    animal.setSpecies(toNative(currentText_));