Рейтинговые книги
Читем онлайн C++. Сборник рецептов - Д. Стефенс

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать

Метод evaluate() класса XPathEvaluator возвращает XObjectPtr, представляющий результат вычисления выражения XPath. Тип данных, на который ссылается XObjectPtr, можно узнать путем его разыменования с получением XObject и вызова метода getType(); затем можно получить доступ к базовым данным при помощи вызова num(), boolean(), str() или nodeset(). Поскольку XPath-выражение в примере 14.23 представляет набор узлов, я использовал метод nodeset() для получения ссылки на NodeRefListBase, который обеспечивает доступ к узлам в наборе с помощью его методов getLength() и item(). Метод item() возвращает указатель на узел XalanNode, метод getNodeValue() которого возвращает строку с интерфейсом, похожим на интерфейс std::basic_string.

Поскольку XPath обеспечивает простой способ определения местоположения узлов в документе XML, возникает естественный вопрос о возможности применения выражений Xalan XPath для получения экземпляров xercesc::DOMNode из xercesc::DOMDocument. На самом деле это возможно, но не совсем удобно, а кроме того, по умолчанию узлы xercesc::DOMNodes, полученные таким способом, представляют дерево документа XML с возможностями только чтения, что уменьшает пользу от применения XPath в качестве средства манипулирования DOM. Существуют способы, позволяющие обойти это ограничение, однако они достаточно сложны и потенциально опасны.

К счастью, библиотека Pathan реализует XPath, совместимый с Xerces и позволяющий легко манипулировать Xerces DOM. Пример 14.24 показывает, как можно использовать Pathan для определения места расположения и удаления узла слона Herby из документа XML, приведенного в примере 14.1, с помощью вычисления XPath-выражения animalList/animal[child::name='Herby']. Сравнение этого примера с примером 14.10 ясно показывает, насколько мощным является язык XPath.

Пример 14.24. Определение местоположения узла и удаление его с использованием библиотеки Pathan

#include <exception>

#include <iostream> // cout

#include <xercesc/dom/DOM.hpp>

#include <xercesc/framework/LocalFileFormatTarget.hpp>

#include <xercesc/util/PlatformUtils.hpp>

#include <pathan/XPathNamespace.hpp>

#include <pathan/XPathResult.hpp>

<include <pathan/XPathEvaluator.hpp>

#include <pathan/XPathExpression.hpp>

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

using namespace std;

using namespace xercesc;

/*

 * Определить XercesInitializer, как это сделано в примере 14.8, а также

 * CircusFrrorHandler и DOMPtr, как это сделано в примере 14.10

 */

int main() {

 try {

  // Инициализировать Xerces и получить DOMImplementation.

  XercesInitializer init;

  DOMImplementation* impl =

   DOMImplementationRegistry::getDOMImplementation(

    fromNative("LS").c_str()

   );

  if (impl == 0) {

   cout << "couldn't create DOM implementationn";

   return EXIT_FAILURE;

  }

  // Сконструировать DOMBuilder для синтаксического анализа

  // документа animals.xml.

  DOMPtr<DOMBuilder> parser =

   static cast<DOMImplementationLS*>(impl)-> createDOMBuilder(

    DOMImplementationLS::MODE_SYNCHRONOUS, 0

   );

  CircusErrorHandler err;

  parser->setErrorHandler(&err);

  // Выполнить синтаксический анализ

  animals.xml. DOMDocument* doc =

   parser->parseURI("animals.xml");

  DOMElement* animalList = doc->getDocumentElement();

  // Создать XPath-выражение.

  auto_ptr<XPathEvaluator>

   evaluator(XPathEvaluator::createEvaluator());

  auto_ptr<XPathNSResolver>

   resolver(evaluator->createNSResolver(animalList));

  auto_ptr<XPathExpression> xpath(

   evaluator->createExpression(FromNative(

    "animalList/animal[child::name='Herby']" ).c_str(), resolver.get()

   )

  );

  auto_ptr<XPathEvaluator> evaluator(XPathEvaluator::createEvaluator());

  auto_ptr<XPathNSResolver> resolver(evaluator->createNSResolver(animalList));

  auto_ptr<XPathExpression> xpath(evaluator->createExpression(

   fromNative("animalList/animal[child::name='Herby']").c_str(),

   resolver.get()

  ));

  // Вычислить выражение.

  XPathResult* result = xpath->evaluate(doc,

   XPathResult::ORDERED_NODE_ITERATOR_TYPE, 0

  );

  DOMNode* herby;

  if (herby = result->iterateNext()) {

   animalList->removeChild(herby);

   herby->release(); // optional

  }

  // Сконструировать DOMWriter для сохранения animals.xml

  DOMPtr<DOMWriter> writer =

   static_cast<DOMImplementationLS->(impl)->createDOMWriter();

  writer->setErrorHandler(&err);

  // Сохранить animals.xml.

  LocalFileFormatTarget file("circus.xml");

  writer->writeNode(&file, *animalList);

 } catch (const DOMException& e) {

  cout << toNative(e.getMessage()) << "n";

  return EXIT_FAILURE;

 } catch (const XPathException &e) {

  cout << e.getString() << "n";

  return EXIT_FAILURE;

 } catch (const exception& e) {

  cout << e.what() << "n";

  return EXIT_FAILURE;

 }

}

Пример 14.24 использует Pathan 1, который реализует рекомендации XPath 1.0; библиотекой Xalan в настоящее время поддерживается именно эта версия. Pathan 2, который в настоящее время доступен в бета-версии, обеспечивает предварительную реализацию рекомендаций XPath 2.0. Pathan 2 представляет собой более точную реализацию стандарта XPath; я рекомендую использовать Pathan 2 вместо Pathan 1, как только станет доступна не бета-версия.

Смотри также

Рецепт 14.7.

14.9. Применение XML для сохранения и восстановления набора объектов

Проблема

Требуется иметь возможность сохранения набора объектов C++ в документе XML и считывания их потом обратно в память.

Решение

Используйте библиотеку Boost Serialization. Эта библиотека позволяет сохранять и восстанавливать объекты, используя классы, называемые архивами. Для использования этой библиотеки вы должны сначала сделать каждый из ваших классов сериализуемым (serializable), что просто означает возможность записи экземпляров класса в архив (это называется сериализацией) и их обратного считывания в память (это называется десериализацией). Затем на этапе выполнения вы можете сохранить ваши объекты в архиве XML, используя оператор <<, и восстановить их, используя оператор >>.

Чтобы сделать класс сериализуемым, добавьте шаблон функции-члена serialize со следующей сигнатурой.

template<typename Archive>

void serialize(Archive& ar, const unsigned int version);

В реализации serialize необходимо обеспечить запись каждого данного-члена класса в указанный архив в виде пары «имя-значение», используя оператор &. Например, если вы хотите сериализовать и десериализовать экземпляры класса Contact из примера 14.2, добавьте функцию-член serialize, как это сделано в примере 14.25.

Пример 14.25. Добавление поддержки сериализации в класс Contact из примера 14.2

#include <boost/serialization/nvp.hpp> // пара "имя-значение"

class Contact {

 ...

private:

 friend class boost::serialization::access;

 template<typename Archive>

 void serialize(Archive& ar, const unsigned int version) {

  // Записать (или считать) каждое данное-член в виде пары имя-значение

  using boost::serialization::make_nvp;

  ar & make_nvp("name", name_);

  ar & make_nvp("phone", phone_);

 }

...

};

Аналогично можно обеспечить сериализацию класса Animal из примера 14.2, как это сделано в примере 14.26.

Пример 14.26. Добавление поддержки сериализации для класса Animal из примера 14.2

...

// Включить поддержку сериализации для boost::gregorian::date

#include <boost/date_time/gregorian/greg_serialize.hpp>

...

class Contact {

 ...

private:

 friend class boost::serialization::access;

 template<typename Archive>

 void serialize(Archive& ar, const unsigned int version) {

  // Записать (или считать) каждое данное-член в виде пары имя-значение

  using boost::serialization::make_nvp;

  ar & make_nvp("name", name_);

  ar & make_nvp("species", species_);

  ar & make_nvp("dateOfBirth", dob_);

  ar & make_nvp("veterinarian", vet_);

  ar & make_nvp("trainer", trainer_);

 }

 ...

};

Теперь вы можете сериализовать Animal, создавая архив XML типа boost::archive::xml_oarchive и записывая информацию о животном в архив, используя оператор <<. Конструктор xml_oarchive в качестве аргумента принимает std::ostream; часто этим аргументом будет поток вывода, используемый для записи в файл, однако в общем случае для записи данных может использоваться ресурс любого типа. После сериализации экземпляра Animal его можно считать обратно в память, конструируя архив XML типа boost::archive::xml_iarchive, подключая его к тому же самому ресурсу, который использовался первым архивом, и применяя оператор >>.

На этой странице вы можете бесплатно читать книгу C++. Сборник рецептов - Д. Стефенс бесплатно.

Оставить комментарий