0
votes

I have some xml like

<node xmlns="path/to/namespace">
  <grammar prop1="bla-bla-bla" prop2="etc">
    <!-- ... -->
  </grammar>
</node>

and I want to get grammar-tag, set my namespace and save all properties(prop1, prop2), children nodes and so on. I just move to grammar-tag and call xmlNodePtr copied = xmlCopyNode(node, 1);. After that I remove some properties, add new and so on(in copied). After that I want to replace namespace "/path/to/namespace" to "/path/to/namespace2". There is no function like xmlRemoveNs or xmlReplaceNs, so I just free namespace and set new.

if (copied->ns)
{
  xmlFree((void*)copied->ns->href);
  copied->ns->href = xmlStrdup((const xmlChar *)"/path/to/namespace2");
}

but it looks weird and a little awful. Is there way to replace namespace, copy without namespace or delete namespace and set new?

2

2 Answers

1
votes

The function xmlFree() only free the memory allocated by some library function and that is not what are you searching for.

Try to use for example xmlSetNsProp():

xmlAttrPtr xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar * name, const xmlChar * value)

Set (or reset) an attribute carried by a node. The ns structure must be in scope, this is not checked

node: the node

ns: the namespace definition

name: the attribute name

value: the attribute value

Returns: the attribute pointer.

You will find more information here: http://xmlsoft.org/html/libxml-tree.html and I think you can find the function that best suits your needs.

In the source code it seems that the namespace is intended as ns->href :

/**
 * xmlSetNsProp:
 * @node:  the node
 * @ns:  the namespace definition
 * @name:  the attribute name
 * @value:  the attribute value
 *
 * Set (or reset) an attribute carried by a node.
 * The ns structure must be in scope, this is not checked
 *
 * Returns the attribute pointer.
 */
xmlAttrPtr xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, const xmlChar *value)
    {
    xmlAttrPtr prop;

    if(ns && (ns->href == NULL))
        return (NULL);
    prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0);
    if(prop != NULL)
        {
        /*
         * Modify the attribute's value.
         */
        if(prop->atype == XML_ATTRIBUTE_ID)
            {
            xmlRemoveID(node->doc, prop);
            prop->atype = XML_ATTRIBUTE_ID;
            }
        if(prop->children != NULL)
            xmlFreeNodeList(prop->children);
        prop->children = NULL;
        prop->last = NULL;
        prop->ns = ns;
        if(value != NULL)
            {
            xmlNodePtr tmp;

            if(!xmlCheckUTF8(value))
                {
                xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr)node->doc,
                NULL);
            if (node->doc != NULL)
            node->doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
            }
        prop->children = xmlNewDocText(node->doc, value);
        prop->last = NULL;
        tmp = prop->children;
        while(tmp != NULL)
            {
            tmp->parent = (xmlNodePtr)prop;
            if(tmp->next == NULL)
                prop->last = tmp;
            tmp = tmp->next;
            }
        }
    if(prop->atype == XML_ATTRIBUTE_ID)
        xmlAddID(NULL, node->doc, value, prop);
    return (prop);
    }
/*
 * No equal attr found; create a new one.
 */
return (xmlNewPropInternal(node, ns, name, value, 0));
}
0
votes

This seems to work

xmlSetNs(copied, nullptr);