/* * 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); }