diff --git a/ChangeLog b/ChangeLog index cb014bf5..3d1c6b5d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +Fri Jun 16 21:37:44 CEST 2006 Kasimier Buchcik + + * tree.c include/libxml/tree.h: Fixed a bug in + xmlDOMWrapAdoptNode(); the tree traversal stopped if the + very first given node had an attribute node :-( This was due + to a missed check in the traversal mechanism. + Expanded the xmlDOMWrapCtxt: it now holds the namespace map + used in xmlDOMWrapAdoptNode() and xmlDOMWrapCloneNode() for + reusal; so the map-items don't need to be created for every + cloning/adoption. Added a callback function to it for + retrieval of xmlNsPtr to be set on node->ns; this is needed + for my custom handling of ns-references in my DOM wrapper. + Substituted code which created the XML namespace decl on + the doc for a call to xmlTreeEnsureXMLDecl(). Removed + those nastly "warnigns" from the docs of the clone/adopt + functions; they work fine on my side. + Mon Jun 12 13:23:11 CEST 2006 Kasimier Buchcik * result/pattern/namespaces: Adjusted the result of a diff --git a/include/libxml/tree.h b/include/libxml/tree.h index b1625745..7f4725fd 100644 --- a/include/libxml/tree.h +++ b/include/libxml/tree.h @@ -54,6 +54,15 @@ typedef xmlEntity *xmlEntityPtr; */ #define BASE_BUFFER_SIZE 4096 +/** + * LIBXML_NAMESPACE_DICT: + * + * Defines experimental behaviour: + * 1) xmlNs gets an additional field @context (a xmlDoc) + * 2) when creating a tree, xmlNs->href is stored in the dict of xmlDoc. + */ +/* #define LIBXML_NAMESPACE_DICT */ + /** * xmlBufferAllocationScheme: * @@ -342,6 +351,7 @@ struct _xmlNs { const xmlChar *href; /* URL for the namespace */ const xmlChar *prefix; /* prefix for the namespace */ void *_private; /* application data */ + struct _xmlDoc *context; /* normally an xmlDoc */ }; /** @@ -508,10 +518,47 @@ struct _xmlDoc { void *psvi; /* for type/PSVI informations */ }; + typedef struct _xmlDOMWrapCtxt xmlDOMWrapCtxt; typedef xmlDOMWrapCtxt *xmlDOMWrapCtxtPtr; + +/** + * xmlDOMWrapAcquireNsFunction: + * @ctxt: a DOM wrapper context + * @node: the context node (element or attribute) + * @nsName: the requested namespace name + * @nsPrefix: the requested namespace prefix + * + * A function called to acquire namespaces (xmlNs) from the wrapper. + * + * Returns an xmlNsPtr or NULL in case of an error. + */ +typedef xmlNsPtr (*xmlDOMWrapAcquireNsFunction) (xmlDOMWrapCtxtPtr ctxt, + xmlNodePtr node, + const xmlChar *nsName, + const xmlChar *nsPrefix); + +/** + * xmlDOMWrapCtxt: + * + * Context for DOM wrapper-operations. + */ struct _xmlDOMWrapCtxt { void * _private; + /* + * The type of this context, just in case we need specialized + * contexts in the future. + */ + int type; + /* + * Internal namespace map used for various operations. + */ + void * namespaceMap; + /* + * Use this one to acquire an xmlNsPtr intended for node->ns. + * (Note that this is not intended for elem->nsDef). + */ + xmlDOMWrapAcquireNsFunction getNsForNodeFunc; }; /** diff --git a/tree.c b/tree.c index 2ec645d6..26e5abdf 100644 --- a/tree.c +++ b/tree.c @@ -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 * @@ -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 @@ -5063,16 +5107,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) @@ -5475,6 +5511,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 @@ -5524,22 +5592,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) || @@ -5666,22 +5725,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) { @@ -6104,7 +6154,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))) { @@ -7161,41 +7211,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 @@ -7269,7 +7284,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 @@ -7277,7 +7291,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; @@ -7351,38 +7365,6 @@ xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, /* xmlNsMapItemPtr *cur return (ret); } -/* -* 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 @@ -7426,6 +7408,46 @@ xmlDOMWrapStoreNs(xmlDocPtr doc, return (ns->next); } +/* +* 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 @@ -7594,7 +7616,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. @@ -7825,7 +7848,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. @@ -7947,10 +7969,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; } } @@ -7962,7 +7984,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) @@ -8009,7 +8030,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. @@ -8110,7 +8132,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. */ @@ -8128,7 +8151,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; @@ -8168,7 +8191,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) && @@ -8374,6 +8397,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 @@ -8391,7 +8416,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; @@ -8404,8 +8429,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. @@ -8437,23 +8483,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) */ @@ -8461,7 +8512,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) || @@ -8480,27 +8531,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)) { @@ -8510,21 +8560,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 { @@ -8568,7 +8617,9 @@ ns_end: */ if ((sourceDoc != NULL) && (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID)) + { xmlRemoveID(sourceDoc, (xmlAttrPtr) cur); + } ((xmlAttrPtr) cur)->atype = 0; ((xmlAttrPtr) cur)->psvi = NULL; } @@ -8623,7 +8674,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? */ @@ -8648,7 +8700,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; } @@ -8663,8 +8719,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); } @@ -8681,9 +8749,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. @@ -8691,11 +8759,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, @@ -8721,10 +8785,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); @@ -8748,6 +8817,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; @@ -8766,23 +8842,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)); @@ -8806,12 +8884,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; @@ -8824,28 +8903,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) { @@ -8883,7 +8965,7 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, */ cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); if (cloneNs == NULL) { - xmlTreeErrMemory("xmlDOMWrapCloneBranch(): " + xmlTreeErrMemory("xmlDOMWrapCloneNode(): " "allocating namespace"); return(-1); } @@ -8898,7 +8980,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? */ @@ -8934,8 +9023,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? */ @@ -8962,15 +9053,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; @@ -9011,15 +9100,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. */ @@ -9036,6 +9124,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) @@ -9051,7 +9140,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; @@ -9069,7 +9159,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. @@ -9161,8 +9251,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? @@ -9311,7 +9413,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,