我正在尝试使用
xmlNode
从 XML 字符串创建 xmlParseBalancedChunkMemory
,但是当 XML 字符串中包含前缀/命名空间时,libxml2
将抛出错误 201 (XML_NS_ERR_UNDEFINED_NAMESPACE
)。解析 XML 字符串的正确方法是什么?
我用来解析 XML 字符串的代码:
xmlNodePtr newNode = nullptr;
// int rc = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
// BAD_CAST content,
// &newNode);
int rc = xmlParseBalancedChunkMemoryRecover(doc, NULL, NULL, 0,
BAD_CAST content,
&newNode, 1);
我正在尝试解析的 XML 字符串:
<ds:X509Certificate>MII...blah</ds:X509Certificate>
抛出的错误:
libxml<Err>: namespace
libxml<Err>: error :
libxml<Err>: Namespace prefix ds on X509Certificate is not defined
libxml<Err>: <ds:X509Certificate>MII...blah</ds:X509Certificate>
libxml<Err>:
我不明白为什么当传递的
doc
已经包含命名空间定义时它会抛出该错误。
<EDSCrate xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
PS:相同的代码在正常的、无前缀的 XML 字符串上运行良好,例如
<a>helloworld</a>
或 helloworld
(文本节点)。
更新:
添加了最小可重复性示例...
libxml2-troubleshoot1$ ./main2
<root xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
XML string is valid
namespace error : Namespace prefix ds on X509Certificate is not defined
<ds:X509Certificate>MII...SigningCertificate</ds:X509Certificate>
^
Namespace is the root cause but how to fix it?
更新2:
我找到了 2 个解决方法(我讨厌)
libxml2
创建节点而不抛出错误...但是,最终结果是我最终在我的节点中拥有额外的 xmlns:ds
属性。我觉得这是 libxml2
无法正确解析可用命名空间的错误。
解决方法#1,创建一个普通节点,然后设置 NS:
xmlNodePtr newNode = nullptr;
xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
BAD_CAST content,
&newNode) == 0;
xmlSetNs(newNode, nsMap[prefix]);
// result:
<ds:X509Certificate xmlns:ds="http://www.w3.org/2000/09/xmldsig#">MII...SigningCertificate</ds:X509Certificate>
解决方法 #2,使用
xmlNewDocNode
:
// I now have to split the name and content
// This probably won't work either if nested content has ns too
// name: "X509Certificate"
// content: "MII...SigningCertificate"
xmlNewDocNode(doc, nsMap[prefix], BAD_CAST name, BAD_CAST content);
// result:
<ds:X509Certificate xmlns:ds="http://www.w3.org/2000/09/xmldsig#">MII...SigningCertificate</ds:X509Certificate>
我终于有时间看到你的代码了。你在干什么?为什么你在那些奇怪的不相关的片段中阅读这个 xml?这是根本错误的。
这是一些非常适合我的测试应用程序:
#include <iostream>
#include <libxml/parser.h>
#include <libxml/tree.h>
const xmlChar* DS_NAMESPACE = BAD_CAST "http://www.w3.org/2000/09/xmldsig#";
constexpr char filename[] = "demo_data.xml";
void process_xml_tree(xmlDocPtr doc)
{
xmlNodePtr root = xmlDocGetRootElement(doc);
xmlNodePtr cur = root->children;
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE &&
xmlStrcmp(cur->name, BAD_CAST "X509Certificate") == 0 &&
xmlStrcmp(cur->ns->href, DS_NAMESPACE) == 0) {
xmlChar* content = xmlNodeGetContent(cur);
if (content != NULL) {
std::cout << "X509Certificate: " << content << std::endl;
xmlFree(content);
}
}
cur = cur->next;
}
}
int main() {
LIBXML_TEST_VERSION
xmlDocPtr doc = xmlReadFile(filename, NULL, 0);
if (doc == NULL) {
perror(filename);
return -1;
}
process_xml_tree(doc);
xmlFreeDoc(doc);
xmlCleanupParser();
return 0;
}
我使用了这个文件
demo_data.xml
:
<?xml version="1.0" encoding="UTF-8" ?>
<root xmlns:ds='http://www.w3.org/2000/09/xmldsig#'>
<ds:X509Certificate>MII...SigningCertificate</ds:X509Certificate>
</root>
输出为:
X509Certificate: MII...SigningCertificate
离题: 如此短的代码发布在问题中,因此无需跳转到其他网站即可清晰可见(我将更新您的问题以涵盖这一点)。