我用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:
不抱怨,但似乎没有注册命名空间。
答案 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;
评论关于名称空间的奇怪讨论:
*[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
”