On Thu, 2005-06-16 at 11:53 +0200, Kasimier Buchcik wrote:
> I'll attach an initial code for a wrapper "unlink" function. The main

I did not. Here it is.

Kasimier
/*
* xmlTreeEnsureXMLDecl:
* @doc: the doc
*
* Ensures that there is an XML namespace declaration on the doc.
*
* Returns the XML ns-struct or NULL on API and internal errors.
*/
static xmlNsPtr
xmlTreeEnsureXMLDecl(xmlDocPtr doc)
{
    if (doc == NULL)
        return (NULL);
    if (doc->oldNs != NULL)
        return (doc->oldNs);
    {
        xmlNsPtr ns;
        ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
        if (ns == NULL) {
            xmlTreeErrMemory(
                "allocating the XML namespace");
            return (NULL);
        }
        memset(ns, 0, sizeof(xmlNs));
        ns->type = XML_LOCAL_NAMESPACE;
        ns->href = xmlStrdup(XML_XML_NAMESPACE);
        ns->prefix = xmlStrdup((const xmlChar *)"xml");
        doc->oldNs = ns;
        return (ns);
    }
}

/*
* xmlTreeAquireDocOldNs:
* @doc: the doc
* @nsName: the namespace name
* @prefix: the prefix
*
* Creates or reuses an xmlNs struct on doc->oldNs with
* the given prefix and namespace name.
*
* Returns the aquired ns struct or NULL in case of an API
*         or internal error.
*/
static xmlNsPtr
xmlTreeAquireDocOldNs(xmlDocPtr doc,
                   const xmlChar *nsName,
                   const xmlChar *prefix)
{
    xmlNsPtr ns;

    if (doc == NULL)
        return (NULL);
    ns = xmlTreeEnsureXMLDecl(doc);
    if (ns == NULL)
        return (NULL);
    if (ns->next != NULL) {
        /* Reuse. */
        ns = ns->next;
        while (ns != NULL) {
            if (((ns->prefix == prefix) ||
                xmlStrEqual(ns->prefix, prefix)) &&
                xmlStrEqual(ns->href, nsName)) {
                return (ns);
            }
            if (ns->next == NULL)
                break;
            ns = ns->next;
        }
    }
    /* Create. */
    ns->next = xmlNewNs(NULL, NULL, NULL);
    if (ns->next == NULL)
        return (NULL);
    ns = ns->next;
    if (doc->dict) {
        if (prefix != NULL)
            ns->prefix = xmlDictLookup(doc->dict, prefix, -1);
        ns->href = xmlDictLookup(doc->dict, nsName, -1);
    } else {
        if (prefix != NULL)
            ns->prefix = BAD_CAST xmlStrdup(prefix);
        ns->href = BAD_CAST xmlStrdup(nsName);
    }
}

static int
xmlDOMWrapAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
                        xmlNsPtr oldNs, xmlNsPtr newNs)
{
    if (*list == NULL) {
        *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
        if (*list == NULL) {
            xmlTreeErrMemory("alloc ns map item");
            return(-1);
        }
        *size = 3;
        *number = 0;
    } else if ((*number) >= (*size)) {
        *size *= 2;
        *list = (xmlNsPtr *) xmlRealloc(*list,
            (*size) * 2 * sizeof(xmlNsPtr));
        if (*list == NULL) {
            xmlTreeErrMemory("realloc ns map item");
            return(-1);
        }
    }
    (*list)[2 * (*number)] = oldNs;
    (*list)[2 * (*number) +1] = newNs;
    (*number)++;
}

/*
* xmlDOMWrapRemoveNode:
*
* @doc: the doc
* @node: the node to be removed.
*
* Unlinks the given node from its owner.
* This will substitute ns-references to node->nsDef for
* ns-references to doc->oldNs, thus ensuring the removed
* branch to be autonomous of any other node in the doc
* wrt to ns-references.
*
* Returns 0 on success, 1 if the node is not supported,
*         -1 on API and internal errors.
*/
static int
xmlDOMWrapRemoveNode(xmlDocPtr doc, xmlNodePtr node)
{
    xmlNsPtr *list = NULL;
    int sizeList, nbList, i, j;
    xmlNsPtr ns;

    if ((node == NULL) || (doc == NULL))
        return (-1);

    /* TODO: 0 or -1 ? */
    if (node->parent == NULL)
        return (0);

    switch (node->type) {
        case XML_TEXT_NODE:
        case XML_CDATA_SECTION_NODE:
        case XML_ENTITY_REF_NODE:
        case XML_PI_NODE:
        case XML_COMMENT_NODE:
            xmlUnlinkNode(node);
            return (0);
        case XML_ELEMENT_NODE:
        case XML_ATTRIBUTE_NODE:
            break;
        default:
            return (1);
    }
    xmlUnlinkNode(node);
    /*
    * Save out-of-scope ns-references in doc->oldNs.
    */
    do {
        switch (node->type) {
            case XML_ELEMENT_NODE:
                if (node->nsDef != NULL) {
                    ns = node->nsDef;
                    do {
                        if (xmlDOMWrapAddNsMapItem2(&list, &sizeList,
                            &nbList, ns, ns) == -1)
                            goto internal_error;
                    } while (ns != NULL);
                }
                /* No break on purpose. */
            case XML_ATTRIBUTE_NODE:
                if (node->ns != NULL) {
                    /*
                    * Find a mapping.
                    */
                    if (list != NULL) {
                        for (i = 0, j = 0; i < nbList; i++, j += 2) {
                            if (node->ns == list[j]) {
                                node->ns = list[++j];
                                goto next_node;
                            }
                        }
                    }
                    /*
                    * Search in doc's oldNs.
                    */
                    if (doc->oldNs != NULL) {
                        ns = doc->oldNs;
                        do {
                            if (node->ns == ns)
                                goto next_node;
                            ns = ns->next;
                        } while (ns != NULL);
                    }
                    /*
                    * Add to doc's oldNs.
                    */
                    ns = xmlTreeAquireDocOldNs(doc, node->ns->href,
                        node->ns->prefix);
                    if (ns == NULL)
                        goto internal_error;
                    /*
                    * Add mapping.
                    */
                    if (xmlDOMWrapAddNsMapItem2(&list, &sizeList,
                        &nbList, node->ns, ns) == -1)
                        goto internal_error;
                    node->ns = ns;
                }
                break;
            default:
                goto next_sibling;
        }

next_node:
        if ((node->type == XML_ELEMENT_NODE) &&
            (node->children != NULL)) {
            node = node->children;
            continue;
        }
next_sibling:
        if (node == NULL)
            break;
        if (node->next != NULL)
            node = node->next;
        else {
            node = node->parent;
            goto next_sibling;
        }
    } while (node != NULL);

    if (list != NULL)
        xmlFree(list);
    return (0);

internal_error:
    if (list != NULL)
        xmlFree(list);
    return (-1);
}
_______________________________________________
xml mailing list, project page  http://xmlsoft.org/
xml@gnome.org
http://mail.gnome.org/mailman/listinfo/xml

Reply via email to