2016-04-11 2 views
1

Я написал парсер C++ XPath с библиотекой libxml++, которая была построена на библиотеке C libxml2. Он отлично работает, когда xmlns отсутствует в xml, но он ломается, когда это пространство имен добавлено.Зарегистрировать пространство имен с помощью libxml ++ для XPath

Пример XML:

<A xmlns="http://some.url/something"> 
    <B> 
    <C>hello world</C> 
    <B> 
</a> 

Пример XPath:

string xpath = "/A/B/C" // returns nothing when xmlns is present in the XML 

Я нашел this answer и пытался регулировать мой XPath к следующему, который делает работу, но это делает XPath вид неприятны для чтения и написать.

string xpath = "/*[name()='A']/*[name()='B']/*[name()='C']" 

В идеале я хочу зарегистрировать пространство имен, чтобы использовать обычные XPaths. Я также просмотрел документацию по libxml ++ и нашел Node.set_namespace, но он просто вызывает исключение, когда я пытаюсь его использовать.

root_node->set_namespace("http://some.url/something"); 
// exception: The namespace (http://some.url/something) has not been declared. 

Однако root_node определенно известно о пространстве имен, когда он анализирует документ XML:

cout << "namespace uri: " << root_node->get_namespace_uri(); 
// namespace uri: http://some.url/something 

На данный момент я из идей, поэтому помощь очень ценится.

EDIT Также пробовал:

Element *root_node = parser->get_document()->get_root_node(); 
root_node->set_namespace_declaration("http://some.url/something","x"); 
cout << "namespace uri: " << root_node->get_namespace_uri() << endl; 
cout << "namespace prefix: " << root_node->get_namespace_prefix() << endl; 
// namespace uri: http://some.url/something 
// namespace prefix: 

не жалуется, но не появляется для регистрации имен.

+0

Я думаю, вам нужно использовать: недействительным xmlpp :: Element :: set_namespace_declaration \t (\t const std :: string & \t ns_uri, const std :: string & \t ns_prefix = std :: string() ) определяется [здесь] (http://libxmlplusplus.sourceforge.net/docs/reference/1.0/html/classxmlpp_1_1Element.html#a2) – SomeDude

+0

Ну, моя переменная - это «Узел», но «Элемент» является дочерним элементом ' Узел, поэтому я мог бы заставить его работать. Я попробую. –

+0

Тип узла может быть типом элемента Element и infact здесь «A» - это элемент, который я предполагаю. – SomeDude

ответ

0

В онлайн-документации для libxml ++ не упоминается, как использовать пространства имен с выражением xpaht. Но, как вы указали, libxml ++ является оберткой для libxml2.

Для libxml2 обратитесь к xmlXPathRegisterNs.

Как всегда с оболочкой сложность скрыть и даже (скорее всего) функциональность.

Обращаясь к исходному коду libxml ++, вы обнаружите, что есть перегрузки, которые используют xmlXPathRegisterNs.

using PrefixNsMap = std::map<Glib::ustring, Glib::ustring> 
NodeSet find(const Glib::ustring& xpath, const PrefixNsMap& namespaces); 

Для этого попробуйте вызвать find с помощью PrefixNsMap с префиксом в качестве ключа.
Update:

xmlpp::Node::PrefixNsMap nsmap; 
nsmap["x"] = "http://some.url/something"; 
auto set = node->find(xpath, nsmap); 
std::cout << set.size() << " nodes have been found:" << std::endl; 

Комментарий к странному дискуссии о пространствах имен:

  • пространства имен по умолчанию часто используется в XML-документах
  • Пространство имен по умолчанию в XML-документ может быть изменен в любом узле и действует до следующего изменения.
  • Пространство имен с префиксом действует только для узлов с этим префиксом.
  • Форма xpath Точка зрения используемого префикса в xml не имеет значения. Вам нужно знать, в каких именах (uri) есть узлы.Каждое пространство имен должно быть зарегистрировано для использования в xpaht с уникальным префиксом пространства имен.
  • Избегайте использования этого *[name()='A'] или * [local-name() = 'A'] `stuff.
+0

Спасибо, но я не уверен, как бы назвал это из libxml ++ без добавления загрузки исходного кода, его реализации и перекомпилировать библиотеку –

+0

@Mike: Посмотрите обновление. –

+0

@Mike: С libxml ++ 3.0 это работает, –

-1

При использовании префикса для Xmlns Я считаю, что ваш XML должен быть:

<x:A xmlns:x="http://some.url/something"> 
    <x:B> 
    <x:C>hello world</x:C> 
    </x:B> 
</x:A> 

и выражение XPath /x:A/x:B/x:C/text() даст «hello world»

+0

Извините, это кажется неправильным. Посмотрите на пространство имен по умолчанию. –

+0

Не могли бы вы объяснить, почему это неправильно, если пользователь хочет использовать пространство имен xml, которое не является стандартным? Взгляните на: http://www.w3schools.com/xml/xml_namespaces.asp. Существует причина, по которой используются префиксы, чтобы избежать конфликтов имен – SomeDude

+0

Нет 'x' здесь префикс namespce и' http: // some .url/something' пространство имен. Предел может быть пустым. Затем у вас есть пространство имен dedault для всех элементов без префикса. –

Смежные вопросы