我正在尝试使用 libxml2 编写 XML 解析器(2.9.1 -> 我知道它很旧,但我现在无法更新它)。我使用的 XML 测试文件是 secret 文件,因此我无法与您分享。但是,在文件中我有以下行:
<?xml version="1.0"?>
<log4j:test xmlns:log4j="http://jakarta.apache.org/log4j/">
我的问题是关于 log4j 命名空间。使用 xmlParseFile 时,我假设它会被自动检测到但不会。我必须显式调用函数 xmlXPathRegisterNs。
所以我的问题是:有没有办法自动注册从文件中读取的命名空间?
在下面的代码中,我不想显式调用 xmlXPathRegisterNs。
感谢您的帮助。
PS:这是我的 beta 测试代码
int main() {
std::string inputFilename = "myfile.xml";
xmlDocPtr document = xmlParseFile(inputFilename.c_str());
if (document == nullptr) {
std::cerr << "Document not parsed successfully" << std::endl;
return -1;
}
xmlXPathContextPtr context = xmlXPathNewContext(document);
if (context == nullptr) {
std::cerr << "Error in xmlXPathNewContext" << std::endl;
return -1;
}
if (xmlXPathRegisterNs(context, BAD_CAST "log4j", BAD_CAST "http://jakarta.apache.org/log4j/") != 0) {
std::cerr << "Unable to register namespace" << std::endl;
return -1;
}
xmlChar *xpath = (xmlChar*) "//log4j:test/log4j:event";
xmlXPathObjectPtr nodesList = xmlXPathEvalExpression(xpath, context);
if (nodesList == nullptr) {
std::cerr << "Error in xmlXPathEvalExpression" << std::endl;
return -1;
}
if (xmlXPathNodeSetIsEmpty(nodesList->nodesetval)) {
std::cerr << "No result found for //log4j:test/log4j:event" << std::endl;
return -1;
} else {
xmlNodeSetPtr nodeset = nodesList->nodesetval;
for (int i{0}; i < nodeset->nodeNr; i++) {
xmlChar *keyword = xmlNodeListGetString(document, nodeset->nodeTab[i]->xmlChildrenNode, 1);
std::cout << "Keyword: " << nodeset->nodeTab[i]->name << std::endl;
xmlFree(keyword);
}
xmlXPathFreeObject(nodesList);
}
xmlFreeDoc(document);
xmlCleanupParser();
return 0;
}
最佳答案
实际上,您并不是在尝试编写 XML 解析器。 libxml2 是一个 XML 解析器。您正在尝试编写一个使用 XML 解析器的应用程序。
当您编写 XPath 表达式时,您可以将任何您喜欢的前缀绑定(bind)到您要查找的元素的 namespace 。您无需知道源文档中使用的前缀。
如果您不想注册 namespace 绑定(bind),那么您的 XPath 表达式不能使用任何 namespace 前缀,并且(假设这是 XPath 1.0)您将不得不使用循环 //*[local-name()='test']/*[local-name()='event']
关于c++ - 有没有办法使用 libxml2 自动检测根标签中写入的命名空间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60521025/