Search code examples
xml-parsingxml-namespaceslibxml2

libxml2 strips prefix off node tags


I have an XML document that looks like this:

<RootNode schemeIdUri="xxx">
    <cenc:pssh>some_data</cenc:pssh>
    <bar:detail>details</bar:detail>
</RootNode>

And there's C++ code here that looks for the detail node like this:

        xmlNode *child;
        for (child = xmlDocGetRootElement(doc)->children; child; child = child->next)
        {
            if (!strcmp((char*)child->name, "bar:detail"))
            {
                auto content = xmlNodeGetContent(child);
                this->detail = (char*) content;
                free(content);
            }
        }

This works with the XML above. But in one case, I instead got XML data that looks like this:

<RootNode xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:cenc="urn:mpeg:cenc:2013" xmlns:bar="urn:extra:details:2020" schemeIdUri="xxx">
    <cenc:pssh>some_data</cenc:pssh>
    <bar:detail>details</bar:detail>
</RootNode>

So, namespaces got added.

The C++ code above then fails, because the child names no longer contain the fully qualified name - they only contain the local part, which in this case is "detail".

Is this intentional? Is it mandatory to strip the bar: prefix in this case? If so, what is then the correct / proper way to look for the details child node with libxml2 in C++?


Solution

  • When working with XML namespaces, you have to check the local name and the namespace URI:

    strcmp((char *) child->name, "detail") == 0 &&
    child->ns != NULL &&
    strcmp((char *) child->ns->href, "urn:extra:details:2020") == 0
    

    Note the first document without namespace declarations is not namespace-well-formed. Also never use the namespace prefix to compare namespaces.