使用libxml ++为XPath注册名称空间

时间:2016-04-11 15:20:49

标签: c++ xml xpath

我用libxml++库编写了一个C ++ XPath解析器,它是在C libxml2库上构建的。当xml中不存在xmlns但在添加该命名空间时它会中断时,它很有效。

示例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']"

理想情况下,我想注册命名空间,以便我可以使用普通的XPath。我还搜索了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

此时我的想法很缺乏,所以非常感谢帮助。

编辑也尝试过:

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: 

不抱怨,但似乎没有注册命名空间。

2 个答案:

答案 0 :(得分:2)

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);

因此尝试使用PrefixNsMap调用find,前缀为key 更新:

 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中使用的前缀并不重要。你需要知道nodeapace(uri)节点是什么。每个命名空间都需要注册,以便在xpaht中使用唯一的命名空间前缀。
  • 避免使用此*[name()='A'] * [local-name()='A']`。

答案 1 :(得分:-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