如何从带有命名空间的字符串构造XML节点?

问题描述 投票:0回答:1

我正在尝试使用

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>
c++ xml xml-parsing xml-namespaces libxml2
1个回答
0
投票

我终于有时间看到你的代码了。你在干什么?为什么你在那些奇怪的不相关的片段中阅读这个 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

离题: 如此短的代码发布在问题中,因此无需跳转到其他网站即可清晰可见(我将更新您的问题以涵盖这一点)。

© www.soinside.com 2019 - 2024. All rights reserved.