diff options
Diffstat (limited to 'tree.c')
-rw-r--r-- | tree.c | 668 |
1 files changed, 395 insertions, 273 deletions
@@ -43,8 +43,16 @@ int __xmlRegisterCallbacks = 0; +/************************************************************************ + * * + * Forward declarations * + * * + ************************************************************************/ + xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns); +static xmlChar* xmlGetPropNodeValueInternal(xmlAttrPtr prop); + /************************************************************************ * * * Tree memory error handler * @@ -337,7 +345,7 @@ xmlSplitQName3(const xmlChar *name, int *len) { #define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l) -#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED) +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined (LIBXML_HTML_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) /** * xmlValidateNCName: * @value: the value to check @@ -1015,6 +1023,42 @@ xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name, (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ xmlFree((char *)(str)); + +/** + * DICT_COPY: + * @str: a string + * + * Copy a string using a "dict" dictionnary in the current scope, + * if availabe. + */ +#define DICT_COPY(str, cpy) \ + if (str) { \ + if (dict) { \ + if (xmlDictOwns(dict, (const xmlChar *)(str))) \ + cpy = (xmlChar *) (str); \ + else \ + cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \ + } else \ + cpy = xmlStrdup((const xmlChar *)(str)); } + +/** + * DICT_CONST_COPY: + * @str: a string + * + * Copy a string using a "dict" dictionnary in the current scope, + * if availabe. + */ +#define DICT_CONST_COPY(str, cpy) \ + if (str) { \ + if (dict) { \ + if (xmlDictOwns(dict, (const xmlChar *)(str))) \ + cpy = (const xmlChar *) (str); \ + else \ + cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \ + } else \ + cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); } + + /** * xmlFreeDtd: * @cur: the DTD structure to free up @@ -4236,7 +4280,7 @@ xmlGetNodePath(xmlNodePtr node) const char *sep; const char *name; char nametemp[100]; - int occur = 0; + int occur = 0, generic; if (node == NULL) return (NULL); @@ -4267,17 +4311,23 @@ xmlGetNodePath(xmlNodePtr node) sep = "/"; next = NULL; } else if (cur->type == XML_ELEMENT_NODE) { + generic = 0; sep = "/"; name = (const char *) cur->name; if (cur->ns) { - if (cur->ns->prefix != NULL) + if (cur->ns->prefix != NULL) { snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s", (char *)cur->ns->prefix, (char *)cur->name); - else - snprintf(nametemp, sizeof(nametemp) - 1, "%s", - (char *)cur->name); - nametemp[sizeof(nametemp) - 1] = 0; - name = nametemp; + nametemp[sizeof(nametemp) - 1] = 0; + name = nametemp; + } else { + /* + * We cannot express named elements in the default + * namespace, so use "*". + */ + generic = 1; + name = "*"; + } } next = cur->parent; @@ -4288,10 +4338,11 @@ xmlGetNodePath(xmlNodePtr node) tmp = cur->prev; while (tmp != NULL) { if ((tmp->type == XML_ELEMENT_NODE) && - (xmlStrEqual(cur->name, tmp->name)) && - ((tmp->ns == cur->ns) || - ((tmp->ns != NULL) && (cur->ns != NULL) && - (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))) + (generic || + (xmlStrEqual(cur->name, tmp->name) && + ((tmp->ns == cur->ns) || + ((tmp->ns != NULL) && (cur->ns != NULL) && + (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))))) occur++; tmp = tmp->prev; } @@ -4299,10 +4350,11 @@ xmlGetNodePath(xmlNodePtr node) tmp = cur->next; while (tmp != NULL && occur == 0) { if ((tmp->type == XML_ELEMENT_NODE) && - (xmlStrEqual(cur->name, tmp->name)) && - ((tmp->ns == cur->ns) || - ((tmp->ns != NULL) && (cur->ns != NULL) && - (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))) + (generic || + (xmlStrEqual(cur->name, tmp->name) && + ((tmp->ns == cur->ns) || + ((tmp->ns != NULL) && (cur->ns != NULL) && + (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))))) occur++; tmp = tmp->next; } @@ -4482,12 +4534,13 @@ xmlDocGetRootElement(xmlDocPtr doc) { /** * xmlDocSetRootElement: * @doc: the document - * @root: the new document root element + * @root: the new document root element, if root is NULL no action is taken, + * to remove a node from a document use xmlUnlinkNode(root) instead. * * Set the root element of the document (doc->children is a list * containing possibly comments, PIs, etc ...). * - * Returns the old root element if any was found + * Returns the old root element if any was found, NULL if root was NULL */ xmlNodePtr xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { @@ -4748,6 +4801,7 @@ xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) { void xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { xmlNsPtr ns; + const xmlChar* fixed; if (cur == NULL) return; switch(cur->type) { @@ -4783,7 +4837,7 @@ xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { if (uri == NULL) doc->URL = NULL; else - doc->URL = xmlStrdup(uri); + doc->URL = xmlPathToURI(uri); return; } } @@ -4791,7 +4845,13 @@ xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); if (ns == NULL) return; - xmlSetNsProp(cur, ns, BAD_CAST "base", uri); + fixed = xmlPathToURI(uri); + if (fixed != NULL) { + xmlSetNsProp(cur, ns, BAD_CAST "base", fixed); + xmlFree(fixed); + } else { + xmlSetNsProp(cur, ns, BAD_CAST "base", uri); + } } #endif /* LIBXML_TREE_ENABLED */ @@ -5055,16 +5115,8 @@ xmlNodeGetContent(xmlNodePtr cur) xmlBufferFree(buffer); return (ret); } - case XML_ATTRIBUTE_NODE:{ - xmlAttrPtr attr = (xmlAttrPtr) cur; - - if (attr->parent != NULL) - return (xmlNodeListGetString - (attr->parent->doc, attr->children, 1)); - else - return (xmlNodeListGetString(NULL, attr->children, 1)); - break; - } + case XML_ATTRIBUTE_NODE: + return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur)); case XML_COMMENT_NODE: case XML_PI_NODE: if (cur->content != NULL) @@ -5403,7 +5455,7 @@ xmlTextMerge(xmlNodePtr first, xmlNodePtr second) { return(first); } -#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) /** * xmlGetNsList: * @doc: the document @@ -5467,6 +5519,38 @@ xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node) } #endif /* LIBXML_TREE_ENABLED */ +/* +* 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); + } +} + /** * xmlSearchNs: * @doc: the document @@ -5516,22 +5600,13 @@ xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) { if (doc == NULL) return(NULL); } - if (doc->oldNs == NULL) { - /* - * Allocate a new Namespace and fill the fields. - */ - doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (doc->oldNs == NULL) { - xmlTreeErrMemory("searching namespace"); - return(NULL); - } - memset(doc->oldNs, 0, sizeof(xmlNs)); - doc->oldNs->type = XML_LOCAL_NAMESPACE; - - doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE); - doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml"); - } - return(doc->oldNs); + /* + * Return the XML namespace declaration held by the doc. + */ + if (doc->oldNs == NULL) + return(xmlTreeEnsureXMLDecl(doc)); + else + return(doc->oldNs); } while (node != NULL) { if ((node->type == XML_ENTITY_REF_NODE) || @@ -5658,22 +5733,13 @@ xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href) if (doc == NULL) return(NULL); } - if (doc->oldNs == NULL) { - /* - * Allocate a new Namespace and fill the fields. - */ - doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (doc->oldNs == NULL) { - xmlTreeErrMemory("searching namespace"); - return (NULL); - } - memset(doc->oldNs, 0, sizeof(xmlNs)); - doc->oldNs->type = XML_LOCAL_NAMESPACE; - - doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE); - doc->oldNs->prefix = xmlStrdup((const xmlChar *) "xml"); - } - return (doc->oldNs); + /* + * Return the XML namespace declaration held by the doc. + */ + if (doc->oldNs == NULL) + return(xmlTreeEnsureXMLDecl(doc)); + else + return(doc->oldNs); } is_attr = (node->type == XML_ATTRIBUTE_NODE); while (node != NULL) { @@ -5871,73 +5937,75 @@ xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { /* * now check for namespace hold by attributes on the node. */ - attr = node->properties; - while (attr != NULL) { - if (attr->ns != NULL) { - /* - * initialize the cache if needed - */ - if (sizeCache == 0) { - sizeCache = 10; - oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * - sizeof(xmlNsPtr)); - if (oldNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - return(-1); - } - newNs = (xmlNsPtr *) xmlMalloc(sizeCache * - sizeof(xmlNsPtr)); - if (newNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(oldNs); - return(-1); - } - } - for (i = 0;i < nbCache;i++) { - if (oldNs[i] == attr->ns) { - attr->ns = newNs[i]; - break; - } - } - if (i == nbCache) { + if (node->type == XML_ELEMENT_NODE) { + attr = node->properties; + while (attr != NULL) { + if (attr->ns != NULL) { /* - * OK we need to recreate a new namespace definition + * initialize the cache if needed */ - n = xmlNewReconciliedNs(doc, tree, attr->ns); - if (n != NULL) { /* :-( what if else ??? */ + if (sizeCache == 0) { + sizeCache = 10; + oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * + sizeof(xmlNsPtr)); + if (oldNs == NULL) { + xmlTreeErrMemory("fixing namespaces"); + return(-1); + } + newNs = (xmlNsPtr *) xmlMalloc(sizeCache * + sizeof(xmlNsPtr)); + if (newNs == NULL) { + xmlTreeErrMemory("fixing namespaces"); + xmlFree(oldNs); + return(-1); + } + } + for (i = 0;i < nbCache;i++) { + if (oldNs[i] == attr->ns) { + attr->ns = newNs[i]; + break; + } + } + if (i == nbCache) { /* - * check if we need to grow the cache buffers. + * OK we need to recreate a new namespace definition */ - if (sizeCache <= nbCache) { - sizeCache *= 2; - oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache * - sizeof(xmlNsPtr)); - if (oldNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(newNs); - return(-1); - } - newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache * - sizeof(xmlNsPtr)); - if (newNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(oldNs); - return(-1); + n = xmlNewReconciliedNs(doc, tree, attr->ns); + if (n != NULL) { /* :-( what if else ??? */ + /* + * check if we need to grow the cache buffers. + */ + if (sizeCache <= nbCache) { + sizeCache *= 2; + oldNs = (xmlNsPtr *) xmlRealloc(oldNs, + sizeCache * sizeof(xmlNsPtr)); + if (oldNs == NULL) { + xmlTreeErrMemory("fixing namespaces"); + xmlFree(newNs); + return(-1); + } + newNs = (xmlNsPtr *) xmlRealloc(newNs, + sizeCache * sizeof(xmlNsPtr)); + if (newNs == NULL) { + xmlTreeErrMemory("fixing namespaces"); + xmlFree(oldNs); + return(-1); + } } + newNs[nbCache] = n; + oldNs[nbCache++] = attr->ns; + attr->ns = n; } - newNs[nbCache] = n; - oldNs[nbCache++] = attr->ns; - attr->ns = n; } } + attr = attr->next; } - attr = attr->next; } /* * Browse the full subtree, deep first */ - if (node->children != NULL && node->type != XML_ENTITY_REF_NODE) { + if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) { /* deep first */ node = node->children; } else if ((node != tree) && (node->next != NULL)) { @@ -6096,7 +6164,7 @@ xmlGetPropNodeValueInternal(xmlAttrPtr prop) * TODO: Do we really always want that? */ if (prop->children != NULL) { - if ((prop->children == prop->last) && + if ((prop->children->next == NULL) && ((prop->children->type == XML_TEXT_NODE) || (prop->children->type == XML_CDATA_SECTION_NODE))) { @@ -6471,7 +6539,9 @@ xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) { if (node == NULL) return(-1); if ((node->type != XML_TEXT_NODE) && - (node->type != XML_CDATA_SECTION_NODE)) { + (node->type != XML_CDATA_SECTION_NODE) && + (node->type != XML_COMMENT_NODE) && + (node->type != XML_PI_NODE)) { #ifdef DEBUG_TREE xmlGenericError(xmlGenericErrorContext, "xmlTextConcat: node is not text nor CDATA\n"); @@ -7153,41 +7223,6 @@ xmlSetCompressMode(int mode) { else xmlCompressMode = mode; } -/* -* xmlDOMWrapNewCtxt: -* -* Allocates and initializes a new DOM-wrapper context. -* -* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror. -*/ -xmlDOMWrapCtxtPtr -xmlDOMWrapNewCtxt(void) -{ - xmlDOMWrapCtxtPtr ret; - - ret = xmlMalloc(sizeof(xmlDOMWrapCtxt)); - if (ret == NULL) { - xmlTreeErrMemory("allocating DOM-wrapper context"); - return (NULL); - } - memset(ret, 0, sizeof(xmlDOMWrapCtxt)); - return (ret); -} - -/* -* xmlDOMWrapFreeCtxt: -* @ctxt: the DOM-wrapper context -* -* Frees the DOM-wrapper context. -*/ -void -xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt) -{ - if (ctxt == NULL) - return; - xmlFree(ctxt); -} - #define XML_TREE_NSMAP_PARENT -1 #define XML_TREE_NSMAP_XML -2 #define XML_TREE_NSMAP_DOC -3 @@ -7261,7 +7296,6 @@ xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap) /* * xmlDOMWrapNsMapAddItem: * @map: the ns-map -* @cur: the current map entry to append a new entry to * @oldNs: the old ns-struct * @newNs: the new ns-struct * @depth: depth and ns-kind information @@ -7269,7 +7303,7 @@ xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap) * Adds an ns-mapping item. */ static xmlNsMapItemPtr -xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, /* xmlNsMapItemPtr *cur, */ +xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, xmlNsPtr oldNs, xmlNsPtr newNs, int depth) { xmlNsMapItemPtr ret; @@ -7344,38 +7378,6 @@ xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, /* xmlNsMapItemPtr *cur } /* -* 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); - } -} - -/* * xmlDOMWrapStoreNs: * @doc: the doc * @nsName: the namespace name @@ -7419,6 +7421,46 @@ xmlDOMWrapStoreNs(xmlDocPtr doc, } /* +* xmlDOMWrapNewCtxt: +* +* Allocates and initializes a new DOM-wrapper context. +* +* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror. +*/ +xmlDOMWrapCtxtPtr +xmlDOMWrapNewCtxt(void) +{ + xmlDOMWrapCtxtPtr ret; + + ret = xmlMalloc(sizeof(xmlDOMWrapCtxt)); + if (ret == NULL) { + xmlTreeErrMemory("allocating DOM-wrapper context"); + return (NULL); + } + memset(ret, 0, sizeof(xmlDOMWrapCtxt)); + return (ret); +} + +/* +* xmlDOMWrapFreeCtxt: +* @ctxt: the DOM-wrapper context +* +* Frees the DOM-wrapper context. +*/ +void +xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt) +{ + if (ctxt == NULL) + return; + if (ctxt->namespaceMap != NULL) + xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap); + /* + * TODO: Store the namespace map in the context. + */ + xmlFree(ctxt); +} + +/* * xmlTreeLookupNsListByPrefix: * @nsList: a list of ns-structs * @prefix: the searched prefix @@ -7586,7 +7628,8 @@ xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number, * This will substitute ns-references to node->nsDef for * ns-references to doc->oldNs, thus ensuring the removed * branch to be autark wrt ns-references. -* WARNING: This function is in a experimental state. +* +* NOTE: This function was not intensively tested. * * Returns 0 on success, 1 if the node is not supported, * -1 on API and internal errors. @@ -7817,7 +7860,6 @@ xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node, * @node: the start node * @prefix: the searched namespace prefix * @retNs: the resulting ns-decl -* @prefixed: if the found ns-decl must have a prefix (for attributes) * * Dynamically searches for a ns-declaration which matches * the given @nsName in the ancestor-or-self axis of @node. @@ -7939,10 +7981,10 @@ ns_next_prefix: return (NULL); if (prefix == NULL) { snprintf((char *) buf, sizeof(buf), - "default%d", counter); + "ns_%d", counter); } else snprintf((char *) buf, sizeof(buf), - "%.30s%d", (char *)prefix, counter); + "%.30s_%d", (char *)prefix, counter); pref = BAD_CAST buf; } } @@ -7954,7 +7996,6 @@ ns_next_prefix: * @ns: the ns-struct to use for the search * @retNs: the found/created ns-struct * @nsMap: the ns-map -* @topmi: the last ns-map entry * @depth: the current tree depth * @ancestorsOnly: search in ancestor ns-decls only * @prefixed: if the searched ns-decl must have a prefix (for attributes) @@ -8001,7 +8042,8 @@ xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc, * If the search should be done in ancestors only and no * @elem (the first ancestor) was specified, then skip the search. */ - if ((! (ancestorsOnly && (elem == NULL))) && (XML_NSMAP_NOTEMPTY(*nsMap))) + if ((XML_NSMAP_NOTEMPTY(*nsMap)) && + (! (ancestorsOnly && (elem == NULL)))) { /* * Try to find an equal ns-name in in-scope ns-decls. @@ -8102,7 +8144,8 @@ typedef enum { * ns-decls where needed. Note that, since prefixes of already existent * ns-decls can be shadowed by this process, it could break QNames in * attribute values or element content. -* WARNING: This function is in a experimental state. +* +* NOTE: This function was not intensively tested. * * Returns 0 if succeeded, -1 otherwise and on API/internal errors. */ @@ -8120,7 +8163,7 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlNsMapItemPtr /* topmi = NULL, */ mi; /* @ancestorsOnly should be set by an option flag. */ int ancestorsOnly = 0; - int optRemoveDedundantNS = + int optRemoveRedundantNS = ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0; xmlNsPtr *listRedund = NULL; int sizeRedund = 0, nbRedund = 0, ret, i, j; @@ -8160,7 +8203,7 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, /* * Lookup the ns ancestor-axis for equal ns-decls in scope. */ - if (optRemoveDedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) { + if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) { XML_NSMAP_FOREACH(nsMap, mi) { if ((mi->depth >= XML_TREE_NSMAP_PARENT) && (mi->shadowDepth == -1) && @@ -8366,6 +8409,8 @@ exit: * shadowed by this process, it could break QNames in attribute * values or element content. * +* NOTE: This function was not intensively tested. +* * Returns 0 if succeeded, -1 otherwise and on API/internal errors. */ static int @@ -8383,7 +8428,7 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, xmlNsPtr ns = NULL; int depth = -1, adoptStr = 1; /* gather @parent's ns-decls. */ - int parnsdone = 0; + int parnsdone; /* @ancestorsOnly should be set per option. */ int ancestorsOnly = 0; @@ -8396,8 +8441,29 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, else adoptStr = 1; + /* + * Get the ns-map from the context if available. + */ + if (ctxt) + nsMap = (xmlNsMapPtr) ctxt->namespaceMap; + /* + * Disable search for ns-decls in the parent-axis of the + * desination element, if: + * 1) there's no destination parent + * 2) custom ns-reference handling is used + */ + if ((destParent == NULL) || + (ctxt && ctxt->getNsForNodeFunc)) + { + parnsdone = 1; + } else + parnsdone = 0; + cur = node; while (cur != NULL) { + /* + * Paranoid source-doc sanity check. + */ if (cur->doc != sourceDoc) { /* * We'll assume XIncluded nodes if the doc differs. @@ -8429,23 +8495,28 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, curElem = cur; depth++; /* - * Namespace declarations. + * Namespace declarations. + * - ns->href and ns->prefix are never in the dict, so + * we need not move the values over to the destination dict. + * - Note that for custom handling of ns-references, + * the ns-decls need not be stored in the ns-map, + * since they won't be referenced by node->ns. */ - if ((ctxt == NULL) && (cur->nsDef != NULL)) { + if ((cur->nsDef) && + ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL))) + { if (! parnsdone) { - if (destParent && (ctxt == NULL)) { - /* - * Gather @parent's in-scope ns-decls. - */ - if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, - destParent) == -1) - goto internal_error; - } + /* + * Gather @parent's in-scope ns-decls. + */ + if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, + destParent) == -1) + goto internal_error; parnsdone = 1; } for (ns = cur->nsDef; ns != NULL; ns = ns->next) { /* - * ns->prefix and ns->href seem not to be in the dict. + * NOTE: ns->prefix and ns->href are never in the dict. * XML_TREE_ADOPT_STR(ns->prefix) * XML_TREE_ADOPT_STR(ns->href) */ @@ -8453,7 +8524,7 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, * Does it shadow any ns-decl? */ if (XML_NSMAP_NOTEMPTY(nsMap)) { - XML_NSMAP_FOREACH(nsMap, mi) { + XML_NSMAP_FOREACH(nsMap, mi) { if ((mi->depth >= XML_TREE_NSMAP_PARENT) && (mi->shadowDepth == -1) && ((ns->prefix == mi->newNs->prefix) || @@ -8472,27 +8543,26 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, goto internal_error; } } - /* No break on purpose. */ + /* No break on purpose. */ case XML_ATTRIBUTE_NODE: - + /* No namespace, no fun. */ if (cur->ns == NULL) goto ns_end; + if (! parnsdone) { - if (destParent && (ctxt == NULL)) { - if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, - destParent) == -1) - goto internal_error; - } + if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, + destParent) == -1) + goto internal_error; parnsdone = 1; } /* * Adopt ns-references. */ - if (XML_NSMAP_NOTEMPTY(nsMap)) { + if (XML_NSMAP_NOTEMPTY(nsMap)) { /* * Search for a mapping. */ - XML_NSMAP_FOREACH(nsMap, mi) { + XML_NSMAP_FOREACH(nsMap, mi) { if ((mi->shadowDepth == -1) && (cur->ns == mi->oldNs)) { @@ -8502,21 +8572,20 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, } } /* - * Start searching for an in-scope ns-decl. - */ - if (ctxt != NULL) { + * No matching namespace in scope. We need a new one. + */ + if ((ctxt) && (ctxt->getNsForNodeFunc)) { /* * User-defined behaviour. */ -#if 0 - ctxt->aquireNsDecl(ctxt, cur->ns, &ns); -#endif + ns = ctxt->getNsForNodeFunc(ctxt, cur, + cur->ns->href, cur->ns->prefix); /* * Insert mapping if ns is available; it's the users fault * if not. */ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, - ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) + cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) goto internal_error; cur->ns = ns; } else { @@ -8560,7 +8629,9 @@ ns_end: */ if ((sourceDoc != NULL) && (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID)) + { xmlRemoveID(sourceDoc, (xmlAttrPtr) cur); + } ((xmlAttrPtr) cur)->atype = 0; ((xmlAttrPtr) cur)->psvi = NULL; } @@ -8615,7 +8686,8 @@ leave_node: break; if ((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_XINCLUDE_START) || - (cur->type == XML_XINCLUDE_END)) { + (cur->type == XML_XINCLUDE_END)) + { /* * TODO: Do we expect nsDefs on XML_XINCLUDE_START? */ @@ -8640,7 +8712,11 @@ leave_node: } if (cur->next != NULL) cur = cur->next; - else { + else if ((cur->type == XML_ATTRIBUTE_NODE) && + (cur->parent->children != NULL)) + { + cur = cur->parent->children; + } else { cur = cur->parent; goto leave_node; } @@ -8655,8 +8731,20 @@ exit: /* * Cleanup. */ - if (nsMap != NULL) - xmlDOMWrapNsMapFree(nsMap); + if (nsMap != NULL) { + if ((ctxt) && (ctxt->namespaceMap == nsMap)) { + /* + * Just cleanup the map but don't free. + */ + if (nsMap->first) { + if (nsMap->pool) + nsMap->last->next = nsMap->pool; + nsMap->pool = nsMap->first; + nsMap->first = NULL; + } + } else + xmlDOMWrapNsMapFree(nsMap); + } return(ret); } @@ -8673,9 +8761,9 @@ exit: * * References of out-of scope ns-decls are remapped to point to @destDoc: * 1) If @destParent is given, then nsDef entries on element-nodes are used -* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used -* This is the case when you have an unliked node and just want to move it -* to the context of +* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used. +* This is the case when you don't know already where the cloned branch +* will be added to. * * If @destParent is given, it ensures that the tree is namespace * wellformed by creating additional ns-decls where needed. @@ -8683,11 +8771,7 @@ exit: * shadowed by this process, it could break QNames in attribute * values or element content. * TODO: -* 1) Support dicts -* Optimize string adoption for equal or none dicts. -* 2) XInclude -* WARNING: This function is in a experimental state and should only be currently -* only be used to test it. +* 1) What to do with XInclude? Currently this returns an error for XInclude. * * Returns 0 if the operation succeeded, * 1 if a node of unsupported (or not yet supported) type was given, @@ -8713,10 +8797,15 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, /* int adoptStr = 1; */ /* gather @parent's ns-decls. */ int parnsdone = 0; - /* @ancestorsOnly should be set per option. */ + /* + * @ancestorsOnly: + * TODO: @ancestorsOnly should be set per option. + * + */ int ancestorsOnly = 0; xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL; - xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL; + xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL; + xmlDictPtr dict; /* The destination dict */ if ((node == NULL) || (resNode == NULL) || (destDoc == NULL)) return(-1); @@ -8740,6 +8829,13 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, if (sourceDoc == NULL) return (-1); + dict = destDoc->dict; + /* + * Reuse the namespace map of the context. + */ + if (ctxt) + nsMap = (xmlNsMapPtr) ctxt->namespaceMap; + *resNode = NULL; cur = node; @@ -8758,23 +8854,25 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, switch (cur->type) { case XML_XINCLUDE_START: case XML_XINCLUDE_END: - /* TODO: What to do with XInclude? */ + /* + * TODO: What to do with XInclude? + */ goto internal_error; break; - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: case XML_ELEMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_COMMENT_NODE: + case XML_PI_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: - case XML_PI_NODE: - case XML_COMMENT_NODE: /* * Nodes of xmlNode structure. */ clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (clone == NULL) { - xmlTreeErrMemory("xmlDOMWrapCloneBranch(): allocating a node"); + xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node"); goto internal_error; } memset(clone, 0, sizeof(xmlNode)); @@ -8798,12 +8896,13 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, */ clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr)); if (clone == NULL) { - xmlTreeErrMemory("xmlDOMWrapCloneBranch(): allocating an attr-node"); + xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node"); goto internal_error; } memset(clone, 0, sizeof(xmlAttr)); /* * Set hierachical links. + * TODO: Change this to add to the end of attributes. */ if (resultClone != NULL) { clone->parent = parentClone; @@ -8816,28 +8915,31 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, resultClone = clone; break; default: - /* TODO */ + /* + * TODO QUESTION: Any other nodes expected? + */ goto internal_error; } clone->type = cur->type; clone->doc = destDoc; - + + /* + * Clone the name of the node if any. + */ if (cur->name == xmlStringText) clone->name = xmlStringText; else if (cur->name == xmlStringTextNoenc) /* - * TODO: xmlStringTextNoenc is never assigned to a node - * in tree.c. + * NOTE: Although xmlStringTextNoenc is never assigned to a node + * in tree.c, it might be set in Libxslt via + * "xsl:disable-output-escaping". */ clone->name = xmlStringTextNoenc; else if (cur->name == xmlStringComment) clone->name = xmlStringComment; else if (cur->name != NULL) { - if ((destDoc != NULL) && (destDoc->dict != NULL)) - clone->name = xmlDictLookup(destDoc->dict, cur->name, -1); - else - clone->name = xmlStrdup(cur->name); + DICT_CONST_COPY(cur->name, clone->name); } switch (cur->type) { @@ -8875,7 +8977,7 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, */ cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); if (cloneNs == NULL) { - xmlTreeErrMemory("xmlDOMWrapCloneBranch(): " + xmlTreeErrMemory("xmlDOMWrapCloneNode(): " "allocating namespace"); return(-1); } @@ -8890,7 +8992,14 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, *cloneNsDefSlot = cloneNs; cloneNsDefSlot = &(cloneNs->next); - if (ctxt == NULL) { + /* + * Note that for custom handling of ns-references, + * the ns-decls need not be stored in the ns-map, + * since they won't be referenced by node->ns. + */ + if ((ctxt == NULL) || + (ctxt->getNsForNodeFunc == NULL)) + { /* * Does it shadow any ns-decl? */ @@ -8926,8 +9035,10 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, break; case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: - if (cur->content) - clone->content = xmlStrdup(cur->content); + /* + * Note that this will also cover the values of attributes. + */ + DICT_COPY(cur->content, clone->content); goto leave_node; case XML_ENTITY_NODE: /* TODO: What to do here? */ @@ -8954,15 +9065,13 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, clone->content = cur->content; clone->children = cur->children; clone->last = cur->last; - } + } goto leave_node; case XML_PI_NODE: - if (cur->content) - clone->content = xmlStrdup(cur->content); + DICT_COPY(cur->content, clone->content); goto leave_node; case XML_COMMENT_NODE: - if (cur->content) - clone->content = xmlStrdup(cur->content); + DICT_COPY(cur->content, clone->content); goto leave_node; default: goto internal_error; @@ -9003,15 +9112,14 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, } } /* - * Start searching for an in-scope ns-decl. + * No matching namespace in scope. We need a new one. */ - if (ctxt != NULL) { + if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) { /* * User-defined behaviour. */ -#if 0 - ctxt->aquireNsDecl(ctxt, cur->ns, &ns); -#endif + ns = ctxt->getNsForNodeFunc(ctxt, cur, + cur->ns->href, cur->ns->prefix); /* * Add user's mapping. */ @@ -9028,6 +9136,7 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, destParent ? curElem : NULL, cur->ns, &ns, &nsMap, depth, + /* if we need to search only in the ancestor-axis */ ancestorsOnly, /* ns-decls must be prefixed for attributes. */ (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) @@ -9043,7 +9152,8 @@ end_ns_reference: * Handle ID attributes. */ if ((clone->type == XML_ATTRIBUTE_NODE) && - (clone->parent != NULL)) { + (clone->parent != NULL)) + { if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) { xmlChar *idVal; @@ -9061,7 +9171,7 @@ end_ns_reference: } /* ** - ** The following will traversing the tree ************************ + ** The following will traverse the tree ************************** ** * * Walk the element's attributes before descending into child-nodes. @@ -9153,8 +9263,20 @@ exit: /* * Cleanup. */ - if (nsMap != NULL) - xmlDOMWrapNsMapFree(nsMap); + if (nsMap != NULL) { + if ((ctxt) && (ctxt->namespaceMap == nsMap)) { + /* + * Just cleanup the map but don't free. + */ + if (nsMap->first) { + if (nsMap->pool) + nsMap->last->next = nsMap->pool; + nsMap->pool = nsMap->first; + nsMap->first = NULL; + } + } else + xmlDOMWrapNsMapFree(nsMap); + } /* * TODO: Should we try a cleanup of the cloned node in case of a * fatal error? @@ -9303,7 +9425,7 @@ internal_error: * Note that, since prefixes of already existent ns-decls can be * shadowed by this process, it could break QNames in attribute * values or element content. -* WARNING: This function is in a experimental state. +* NOTE: This function was not intensively tested. * * Returns 0 if the operation succeeded, * 1 if a node of unsupported type was given, |