xml-tag 可以使用两个名称空间还是 libxml2 错误?

Is xml-tag could use two namespaces or this is libxml2 bug?

我有以下 有效 XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <aaa xmlns:de="http://www.dolby.com/dcinema/ws/smi/v11/SPL" atr="abc" xmlns:fe="http://somewhere">
   some text
   <de:bbb atr1="abb" atr2="baa" >aaa</de:bbb>
   <de:ccc>aaa</de:ccc>
   <fe:ddd>bbb</fe:ddd>
   some more text
  </aaa>

以及以下 C 代码:

#include <stdio.h>
#include <libxml/xmlreader.h>
#include <libxml/tree.h>

char xml_data[] = {
    "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
    "  <aaa xmlns:de=\"http://www.dolby.com/dcinema/ws/smi/v11/SPL\" "
    "       atr=\"abc\""
    "       xmlns:fe=\"http://somewhere\">\n"
    "   some text\n"
    "   <de:bbb atr1=\"abb\"  atr2=\"baa\" >aaa</de:bbb>\n"
    "   <de:ccc>aaa</de:ccc>\n"
    "   <fe:ddd>bbb</fe:ddd>\n"
    "   some more text\n"
    "  </aaa>"
};

void printns(xmlNsPtr ns, int deep, char * marker)
{
    while (ns)
    {
        printf("%*c%s+%s\n", deep * 5 + 1, ' ', marker, ns->prefix);
        ns = ns->next;
    }
}

void printelem(xmlNodePtr ptr, int deep)
{
    printf("%*c%s\n", deep * 5, ' ', ptr->name);
    if (ptr->type == XML_ELEMENT_NODE) 
    {
        printns(ptr->nsDef, deep, "d");
        printns(ptr->ns,    deep, "u");
    }

    if (ptr->xmlChildrenNode) printelem(ptr->xmlChildrenNode, deep+1);

    if (ptr->next) printelem(ptr->next, deep);
}

int main(void)
{
    LIBXML_TEST_VERSION
    xmlInitParser();

    xmlDocPtr doc;
    doc = xmlReadDoc(BAD_CAST xml_data, NULL, NULL, XML_PARSE_NOBLANKS);

    printelem(doc->xmlChildrenNode, 1);

    xmlFreeDoc(doc);
}

这会产生以下输出:

 aaa
  d+de
  d+fe
      text
      bbb
       u+de
       u+fe
           text
      text
      ccc
       u+de
       u+fe
           text
      text
      ddd
       u+fe
           text
      text

如您所见,libxml2 说 bbb 和 ccc 同时有两个命名空间,而 ddd 有一个命名空间,正如预期的那样。这是一些我不知道的 xml 标准规则还是这个 libxml2 错误?

XML 元素的名称显然只能有一个命名空间。所以你不应该把struct _xmlNode中的ns成员当成一个链表。它实际上指向祖先元素的 nsDef 条目。仅使用 next 指针来迭代 nsDef。如果您更改 printns 中的 printf 语句以同时显示 xmlNs 结构

的地址
printf("%*c%s+%s [%p]\n", deep * 5 + 1, ' ', marker, ns->prefix,
       (void*)ns);

输出变为

 aaa
  d+de [0x9e9aff0]
  d+fe [0x9e9b1a0]
      text
      bbb
       u+de [0x9e9aff0]  // same as first entry in nsDef of aaa
       u+fe [0x9e9b1a0]  // should be ignored
           text
      text
      ccc
       u+de [0x9e9aff0]  // same as first entry in nsDef of aaa
       u+fe [0x9e9b1a0]  // should be ignored
           text
      text
      ddd
       u+fe [0x9e9b1a0]  // same as second entry in nsDef of aaa
           text
      text

请注意 ns 始终指向元素的正确 xmlNs