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

  //       и 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_,

 // подготавливая обратный вызов 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.