Метод 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 implementation\n";
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, как только станет доступна не бета-версия.