[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [xml] redicting parts of trees



Hi,

On Thu, 2005-06-16 at 09:10 -0400, Rob Richards wrote:
[...]
> Rob

I attached the current diffs for tree.c and tree.h.

There would be three public functions:

int 
xmlDOMWrapReconcileNamespaces(xmlFooCtxtPtr ctxt,
  xmlNodePtr elem,
  int options);

int
xmlDOMWrapAdoptNode(xmlFooCtxtPtr ctxt,
  xmlDocPtr sourceDoc,
  xmlNodePtr node,
  xmlDocPtr destDoc,		    
  xmlNodePtr destParent,
  int options);

int
xmlDOMWrapRemoveNode(xmlFooCtxtPtr ctxt,
  xmlDocPtr doc,
  xmlNodePtr node);

That makes an addition of ~35 KB to tree.c :-/
Maybe a separate file for DOM-wrapper helper functions would be an
option. Since this all is eventually more code than you expected, I
just post the diff here, and would like to wait for Daniel
to return from vacations for discussion, before exposing anything
to the API.

Additionally there are some tests which can be generated
with the attached files:
"test-adopt.xml" - the test definitions
"test-adopt-to-c.xsl" - the transformation file to C

xsltproc -o test-adopt.c test-adopt-to-c.xsd test-adopt.xml

We could transform the test-definitions to python, when/if
the functions will become available to python.

Open issues:
1. What exactly to do with XIncluded pieces?
2. Design the custom context; it should be used for a
   yet-to-write node-copy function as well.
3. More?

If you have a test-scenario in your head, please send it either
by using the structure as in "test-adopt.xml" or just
describe the scenario, so we can add the test.

Greetings,

Kasimier

Index: tree.c
===================================================================
RCS file: /cvs/gnome/libxml2/tree.c,v
retrieving revision 1.344
diff -c -r1.344 tree.c
*** tree.c	20 Jun 2005 17:17:54 -0000	1.344
--- tree.c	22 Jun 2005 15:05:42 -0000
***************
*** 7127,7131 ****
--- 7127,8654 ----
      else xmlCompressMode = mode;
  }
  
+ #define XML_TREE_NSMAP_PARENT -1
+ #define XML_TREE_NSMAP_XML -2
+ #define XML_TREE_NSMAP_DOC -3
+ #define XML_TREE_NSMAP_CUSTOM -4
+ 
+ typedef struct xmlNsMapItem *xmlNsMapItemPtr;
+ struct xmlNsMapItem {
+     xmlNsMapItemPtr next;
+     xmlNsMapItemPtr prev;
+     xmlNsPtr oldNs; /* old ns decl reference */
+     xmlNsPtr newNs; /* new ns decl reference */
+     int shadowDepth; /* Shadowed at this depth */
+     /*
+     * depth:
+     * >= 0 == @node's ns-decls
+     * -1   == @parent's ns-decls
+     * -2   == @parent's out-of-scope ns-decls
+     * -3   == the doc->oldNs XML ns-decl
+     * -4   == the doc->oldNs storage ns-decls
+     */
+     int depth;
+ };
+ 
+ /*
+ * xmlTreeAddNsMapItem:
+ * @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
+ * 
+ * Frees the ns-map
+ */
+ static xmlNsMapItemPtr
+ xmlDOMWrapNSNormAddNsMapItem(xmlNsMapItemPtr *map,
+ 			     xmlNsMapItemPtr *cur,
+ 			     xmlNsPtr oldNs,
+ 			     xmlNsPtr newNs,
+ 			     int depth)
+ {
+     xmlNsMapItemPtr ret;
+      
+     if ((cur != NULL) && (*cur != NULL) && ((*cur)->next != NULL)) {
+ 	/*
+ 	* Reuse.
+ 	*/
+ 	ret = (*cur)->next;
+ 	*cur = ret;
+     } else {
+ 	ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem));
+ 	if (ret == NULL) {
+ 	    xmlTreeErrMemory("allocating namespace map item");
+ 	    return (NULL);
+ 	}
+ 	memset(ret, 0, sizeof(struct xmlNsMapItem));
+ 	if (*map == NULL) {
+ 	    /*
+ 	    * First ever.
+ 	    */
+ 	    *map = ret;
+ 	    ret->prev = ret;
+ 	    if (cur != NULL)
+ 		*cur = ret;
+ 	} else {
+ 	    if (cur) {
+ 		/*
+ 		* Append.
+ 		*/
+ 		(*cur)->next = ret;
+ 		ret->prev = *cur;
+ 		*cur = ret;
+ 	    } else {
+ 		/*
+ 		* Set on first position.
+ 		*/
+ 		ret->next = (*map);
+ 		ret->prev = (*map)->prev;
+ 		(*map)->prev = ret;
+ 		*map = ret;
+ 	    }
+ 	}
+     }
+     ret->oldNs = oldNs;
+     ret->newNs = newNs;
+     ret->shadowDepth = -1;
+     ret->depth = depth;
+     return (ret);
+ }
+ 
+ /*
+ * xmlTreeFreeNsMap:
+ * @map: the ns-map
+ * 
+ * Frees the ns-map
+ */
+ static void
+ xmlDOMWrapNSNormFreeNsMap(xmlNsMapItemPtr map)
+ {    
+     xmlNsMapItemPtr mi = map, miprev;
+ 
+     while (mi != NULL) {
+ 	miprev = mi;
+ 	mi = mi->next;
+ 	xmlFree(miprev);
+     }
+ }
+ 
+ /*
+ * 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
+ * @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
+ xmlDOMWrapStoreNs(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, nsName, prefix);
+     return (ns->next);
+ }
+ 
+ /*
+ * xmlTreeLookupNsListByPrefix:
+ * @nsList: a list of ns-structs
+ * @prefix: the searched prefix
+ * 
+ * Searches for a ns-decl with the given prefix in @nsList.
+ * 
+ * Returns the ns-decl if found, NULL if not found and on
+ *         API errors.
+ */
+ static xmlNsPtr
+ xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix)
+ {
+     if (nsList == NULL)
+ 	return (NULL);
+     {
+ 	xmlNsPtr ns;
+ 	ns = nsList;
+ 	do {
+ 	    if ((prefix == ns->prefix) ||
+ 		xmlStrEqual(prefix, ns->prefix)) {
+ 		return (ns);
+ 	    }
+ 	    ns = ns->next;
+ 	} while (ns != NULL);
+     }
+     return (NULL);
+ }
+ 
+ /*
+ *
+ * xmlTreeGetInScopeNamespaces:
+ * @map: the namespace map
+ * @node: the node to start with
+ * 
+ * Puts in-scope namespaces into the ns-map.
+ * 
+ * Returns 0 on success, -1 on API or internal errors.
+ */
+ static int
+ xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapItemPtr *map,
+ 				xmlNodePtr node)
+ {
+     xmlNodePtr cur;
+     xmlNsPtr ns;
+     xmlNsMapItemPtr mi;
+     int shadowed;
+ 
+     if ((map == NULL) || (*map != NULL))
+ 	return (-1);
+     /*
+     * Get in-scope ns-decls of @parent.
+     */
+     cur = node;
+     while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) {
+ 	if (cur->type == XML_ELEMENT_NODE) {
+ 	    if (cur->nsDef != NULL) {
+ 		ns = cur->nsDef;
+ 		do {
+ 		    shadowed = 0;
+ 		    if (*map != NULL) {
+ 			/*
+ 			* Skip shadowed prefixes.
+ 			*/
+ 			for (mi = *map; mi != NULL; mi = mi->next) {
+ 			    if ((ns->prefix == mi->newNs->prefix) ||
+ 				xmlStrEqual(ns->prefix, mi->newNs->prefix)) {
+ 				shadowed = 1;
+ 				break;
+ 			    }
+ 			}
+ 		    }
+ 		    /*
+ 		    * Insert mapping.
+ 		    */
+ 		    mi = xmlDOMWrapNSNormAddNsMapItem(map, NULL, NULL,
+ 			ns, XML_TREE_NSMAP_PARENT);
+ 		    if (mi == NULL)
+ 			return (-1);
+ 		    if (shadowed)
+ 			mi->shadowDepth = 0;
+ 		    ns = ns->next;
+ 		} while (ns != NULL);
+ 	    }
+ 	}
+ 	cur = cur->parent;
+     }
+     return (0);
+ }
+ 
+ /*
+ * XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
+ * otherwise copy it, when it was in the source-dict.
+ */
+ #define XML_TREE_ADOPT_STR(str) \
+     if (adoptStr && (str != NULL)) { \
+ 	if (destDoc->dict) { \
+ 	    str = xmlDictLookup(destDoc->dict, str, -1); \
+ 	} else if ((sourceDoc) && (sourceDoc->dict) && \
+ 	    xmlDictOwns(sourceDoc->dict, str)) { \
+ 	    str = BAD_CAST xmlStrdup(str); \
+ 	} \
+     }
+ 
+ /*
+ * XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
+ * put it in dest-dict or copy it.
+ */
+ #define XML_TREE_ADOPT_STR_2(str) \
+     if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
+ 	(sourceDoc->dict != NULL) && \
+ 	xmlDictOwns(sourceDoc->dict, cur->content)) { \
+ 	if (destDoc->dict) \
+ 	    cur->content = (xmlChar *) \
+ 		xmlDictLookup(destDoc->dict, cur->content, -1); \
+ 	else \
+ 	    cur->content = xmlStrdup(BAD_CAST cur->content); \
+     }
+ 
+ /*
+ * xmlDOMWrapNSNormAddNsMapItem2:
+ *
+ * For internal use. Adds a ns-decl mapping.
+ *
+ * Returns 0 on success, -1 on internal errors. 
+ */
+ static int
+ xmlDOMWrapNSNormAddNsMapItem2(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)++;
+     return (0);
+ }
+ 
+ /*
+ * 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 autark wrt ns-references.
+ *
+ * Returns 0 on success, 1 if the node is not supported,
+ *         -1 on API and internal errors. 
+ */
+ int
+ xmlDOMWrapRemoveNode(xmlFooCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr node)
+ {
+     xmlNsPtr *list = NULL;
+     int sizeList, nbList, i, j;
+     xmlNsPtr ns;
+ 
+     if ((node == NULL) || (doc == NULL) || (node->doc != doc))
+ 	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 ((ctxt == NULL) && (node->nsDef != NULL)) {
+ 		    ns = node->nsDef;
+ 		    do {
+ 			if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
+ 			    &nbList, ns, ns) == -1)
+ 			    goto internal_error;
+ 			ns = ns->next;
+ 		    } 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;
+ 			    }
+ 			}
+ 		    }
+ 		    ns = NULL;
+ 		    if (ctxt != NULL) {
+ 			/*
+ 			* User defined.
+ 			*/
+ 		    } else {
+ 			/*
+ 			* Add to doc's oldNs.
+ 			*/
+ 			ns = xmlDOMWrapStoreNs(doc, node->ns->href,
+ 			    node->ns->prefix);
+ 			if (ns == NULL)
+ 			    goto internal_error;
+ 		    }
+ 		    if (ns != NULL) {
+ 			/*
+ 			* Add mapping.
+ 			*/
+ 			if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
+ 			    &nbList, node->ns, ns) == -1)
+ 			    goto internal_error;
+ 		    }
+ 		    node->ns = ns;
+ 		}
+ 		if ((node->type == XML_ELEMENT_NODE) &&
+ 		    (node->properties != NULL)) {
+ 		    node = (xmlNodePtr) node->properties;
+ 		    continue;
+ 		}
+ 		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);
+ }
+ 
+ /*
+ * xmlSearchNsByHrefStrict:
+ * @doc: the document
+ * @node: the start node
+ * @nsName: the searched namespace name
+ * @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.
+ *
+ * Returns 1 if a ns-decl was found, 0 if not and -1 on API
+ *         and internal errors.
+ */
+ static int
+ xmlSearchNsByHrefStrict(xmlDocPtr doc, xmlNodePtr node, const xmlChar* nsName,
+ 			 xmlNsPtr *retNs, int prefixed)
+ {
+     xmlNodePtr cur, prev = NULL, out = NULL;
+     xmlNsPtr ns, prevns;
+ 
+     if ((doc == NULL) || (nsName == NULL) || (retNs == NULL))
+ 	return (-1);
+ 
+     *retNs = NULL;
+     if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
+ 	*retNs = xmlTreeEnsureXMLDecl(doc);
+ 	if (*retNs == NULL)
+ 	    return (-1);
+ 	return (1);
+     }
+     cur = node;
+     do {
+ 	if (cur->type == XML_ELEMENT_NODE) {
+ 	    if (cur->nsDef != NULL) {
+ 		for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
+ 		    if (prefixed && (ns->prefix == NULL))
+ 			continue;
+ 		    if (prev != NULL) {
+ 			/*
+ 			* Check the last level of ns-decls for a
+ 			* shadowing prefix.
+ 			*/
+ 			prevns = prev->nsDef;
+ 			do {
+ 			    if ((prevns->prefix == ns->prefix) ||
+ 				((prevns->prefix != NULL) &&
+ 				(ns->prefix != NULL) &&
+ 				xmlStrEqual(prevns->prefix, ns->prefix))) {
+ 				/*
+ 				* Shadowed.
+ 				*/
+ 				break;
+ 			    }
+ 			    prevns = prevns->next;
+ 			} while (prevns != NULL);
+ 			if (prevns != NULL)
+ 			    continue;
+ 		    }
+ 		    /*
+ 		    * Ns-name comparison.
+ 		    */
+ 		    if ((nsName == ns->href) ||
+ 			xmlStrEqual(nsName, ns->href)) {
+ 			/*
+ 			* At this point the prefix can only be shadowed,
+ 			* if we are the the (at least) 3rd level of
+ 			* ns-decls.
+ 			*/
+ 			if (out) {
+ 			    int ret;
+ 			    
+ 			    ret = xmlNsInScope(doc, node, prev, ns->prefix);
+ 			    if (ret < 0)
+ 				return (-1);
+ 			    /*
+ 			    * TODO: Should we try to find a matching ns-name
+ 			    * only once? This here keeps on searching.
+ 			    * I think we should try further since, there might
+ 			    * be an other matching ns-decl with an unshadowed
+ 			    * prefix.
+ 			    */
+ 			    if (! ret)
+ 				continue;
+ 			}
+ 			*retNs = ns;
+ 			return (1);
+ 		    }
+ 		}
+ 		out = prev;
+ 		prev = cur;
+ 	    }
+ 	} else if ((node->type == XML_ENTITY_REF_NODE) ||
+             (node->type == XML_ENTITY_NODE) ||
+             (node->type == XML_ENTITY_DECL))
+ 	    return (0);
+ 	cur = cur->parent;
+     } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
+     return (0);
+ }
+ 
+ /*
+ * xmlDOMWrapNSNormDeclareNsForced:
+ * @doc: the doc
+ * @elem: the element-node to declare on
+ * @nsName: the namespace-name of the ns-decl
+ * @prefix: the preferred prefix of the ns-decl
+ * @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls
+ *
+ * Declares a new namespace on @elem. It tries to use the
+ * given @prefix; if a ns-decl with the given prefix is already existent
+ * on @elem, it will generate an other prefix.
+ *
+ * Returns 1 if a ns-decl was found, 0 if not and -1 on API
+ *         and internal errors.
+ */
+ static xmlNsPtr
+ xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc,
+ 				xmlNodePtr elem,
+ 				const xmlChar *nsName,
+ 				const xmlChar *prefix,
+ 				int checkShadow)
+ {
+ 
+     xmlNsPtr ret;
+     char buf[50];
+     const xmlChar *pref;
+     int counter = 0;
+     /*
+     * Create a ns-decl on @anchor.
+     */
+     pref = prefix;
+     while (1) {
+ 	/*
+ 	* Lookup whether the prefix is unused in elem's ns-decls.
+ 	*/
+ 	if ((elem->nsDef != NULL) &&
+ 	    (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL))
+ 	    goto ns_next_prefix;
+ 	if (checkShadow && elem->parent &&
+ 	    ((xmlNodePtr) elem->parent->doc != elem->parent)) {
+ 	    /*
+ 	    * Does it shadow ancestor ns-decls?
+ 	    */
+ 	    if (xmlSearchNs(doc, elem->parent, pref) != NULL)
+ 		goto ns_next_prefix;
+ 	}
+ 	ret = xmlNewNs(NULL, nsName, pref);
+ 	if (ret == NULL)
+ 	    return (NULL);
+ 	if (elem->nsDef == NULL)
+ 	    elem->nsDef = ret;
+ 	else {
+ 	    xmlNsPtr ns2 = elem->nsDef;
+ 	    while (ns2->next != NULL)
+ 		ns2 = ns2->next;
+ 	    ns2->next = ret;
+ 	}
+ 	return (ret);
+ ns_next_prefix:
+ 	counter++;
+ 	if (counter > 1000)
+ 	    return (NULL);
+ 	if (prefix == NULL) {
+ 	    snprintf((char *) buf, sizeof(buf),
+ 		"default%d", counter);
+ 	} else
+ 	    snprintf((char *) buf, sizeof(buf),
+ 	    "%.30s%d", (char *)prefix, counter);
+ 	pref = BAD_CAST buf;
+     }
+ }
+ 
+ /*
+ * xmlDOMWrapNSNormAquireNormalizedNs:
+ * @doc: the doc
+ * @elem: the element-node to declare namespaces on
+ * @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)
+ *
+ * Searches for a matching ns-name in the ns-decls of @nsMap, if not
+ * found it will either declare it on @elem, or store it in doc->oldNs.
+ * If a new ns-decl needs to be declared on @elem, it tries to use the
+ * @ns->prefix for it, if this prefix is already in use on @elem, it will
+ * change the prefix or the new ns-decl.
+ *
+ * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
+ */
+ static int
+ xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc,
+ 				   xmlNodePtr elem,
+ 				   xmlNsPtr ns,
+ 				   xmlNsPtr *retNs,
+ 				   xmlNsMapItemPtr *nsMap,
+ 				   xmlNsMapItemPtr *topmi,
+ 				   int depth,
+ 				   int ancestorsOnly,
+ 				   int prefixed)
+ {
+     xmlNsMapItemPtr mi;    
+ 
+     if ((doc == NULL) || (ns == NULL) || (retNs == NULL) ||
+ 	(nsMap == NULL) || (topmi == NULL))
+ 	return (-1);
+ 
+     *retNs = NULL;
+     /*
+     * Handle XML namespace.
+     */
+     if ((ns->prefix) &&
+ 	(ns->prefix[0] == 'x') &&
+ 	(ns->prefix[1] == 'm') &&
+ 	(ns->prefix[2] == 'l') &&
+ 	(ns->prefix[3] == 0)) {
+ 	/*
+ 	* Insert XML namespace mapping.
+ 	*/
+ 	*retNs = xmlTreeEnsureXMLDecl(doc);
+ 	if (*retNs == NULL)
+ 	    return (-1);
+ 	return (0);
+     }
+     /*
+     * 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))) &&
+ 	(*nsMap != NULL)) {
+ 	
+ 	/*
+ 	* Try to find an equal ns-name in in-scope ns-decls.
+ 	*/
+ 	for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
+ 	    
+ 	    if ((mi->depth >= XML_TREE_NSMAP_PARENT) && 				
+ 		/* 
+ 		* This should be turned on to gain speed, if one knows
+ 		* that the branch itself was already ns-wellformed and no
+ 		* stale references existed. I.e. it searches in the ancestor
+ 		* axis only.
+ 		*/
+ 		((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) &&
+ 		/* Skip shadowed prefixes. */
+ 		(mi->shadowDepth == -1) &&		
+ 		/* Skip xmlns="" or xmlns:foo="". */
+ 		((mi->newNs->href != NULL) &&
+ 		(mi->newNs->href[0] != 0)) &&		
+ 		/* Ensure a prefix if wanted. */
+ 		((! prefixed) || (mi->newNs->prefix != NULL)) &&
+ 		/* Equal ns name */
+ 		((mi->newNs->href == ns->href) ||
+ 		xmlStrEqual(mi->newNs->href, ns->href))) {
+ 		/* Set the mapping. */
+ 		mi->oldNs = ns;
+ 		*retNs = mi->newNs;
+ 		return (0);
+ 	    }
+ 	}
+     }
+     /*
+     * No luck, the namespace is out of scope or shadowed.
+     */
+     if (elem == NULL) {
+ 	xmlNsPtr tmpns;
+ 
+ 	/*
+ 	* Store ns-decls in "oldNs" of the document-node.
+ 	*/
+ 	tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix);
+ 	if (tmpns == NULL)
+ 	    return (-1);
+ 	/*
+ 	* Insert mapping.
+ 	*/	
+ 	if (xmlDOMWrapNSNormAddNsMapItem(nsMap, NULL, ns,
+ 		tmpns, XML_TREE_NSMAP_DOC) == NULL) {
+ 	    xmlFreeNs(tmpns);
+ 	    return (-1);
+ 	}
+ 	*retNs = tmpns;
+     } else {
+ 	xmlNsPtr tmpns;
+ 
+ 	tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href,
+ 	    ns->prefix, 0);
+ 	if (tmpns == NULL)
+ 	    return (-1);
+ 
+ 	if (*nsMap != NULL) {
+ 	    /*
+ 	    * Does it shadow ancestor ns-decls?
+ 	    */		
+ 	    for (mi = *nsMap; mi != (*topmi)->next; mi = mi->next) {
+ 		if ((mi->depth < depth) &&
+ 		    (mi->shadowDepth == -1) &&
+ 		    ((ns->prefix == mi->newNs->prefix) ||
+ 		    xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
+ 		    /*
+ 		    * Shadows.
+ 		    */
+ 		    mi->shadowDepth = depth;
+ 		    break;
+ 		}
+ 	    }
+ 	}
+ 	if (xmlDOMWrapNSNormAddNsMapItem(nsMap, topmi, ns,
+ 		tmpns, depth) == NULL) {
+ 	    xmlFreeNs(tmpns);
+ 	    return (-1);
+ 	}
+ 	*retNs = tmpns;
+     }
+     return (0);
+ }
+ 
+ /*
+ * xmlDOMWrapReconcileNamespaces:
+ * @elem: the element-node
+ * @options: option flags
+ *
+ * Ensures that ns-references point to ns-decls hold on element-nodes.
+ * Ensures that the tree is namespace wellformed by creating additional
+ * 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.
+ *
+ * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
+ */
+ int
+ xmlDOMWrapReconcileNamespaces(xmlFooCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr elem,
+ 			      int options ATTRIBUTE_UNUSED)
+ {
+     int depth = -1, adoptns = 0, parnsdone = 0;
+     xmlNsPtr ns;
+     xmlDocPtr doc;
+     xmlNodePtr cur, curElem = NULL;
+     xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
+     /* @ancestorsOnly should be set by an option flag. */
+     int ancestorsOnly = 0;
+ 
+     if ((elem == NULL) || (elem->doc == NULL) ||
+ 	(elem->type != XML_ELEMENT_NODE))
+ 	return (-1);
+ 
+     doc = elem->doc;
+     cur = elem;
+     do {
+ 	switch (cur->type) {
+ 	    case XML_ELEMENT_NODE:
+ 		adoptns = 1;
+ 		curElem = cur;
+ 		depth++;
+ 		/*
+ 		* Namespace declarations.
+ 		*/
+ 		if (cur->nsDef != NULL) {
+ 		    for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
+ 			if (! parnsdone) {
+ 			    if ((elem->parent) &&
+ 				((xmlNodePtr) elem->parent->doc != elem->parent)) {
+ 				/*
+ 				* Gather ancestor in-scope ns-decls.
+ 				*/
+ 				if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
+ 				    elem->parent) == -1)
+ 				    goto internal_error;
+ 				if (nsMap != NULL)
+ 				    topmi = nsMap->prev;
+ 			    }
+ 			    parnsdone = 1;
+ 			}
+ 			/*
+ 			* Skip ns-references handling if the referenced
+ 			* ns-decl is declared on the same element.
+ 			*/
+ 			if ((cur->ns != NULL) && adoptns && (cur->ns == ns))
+ 			    adoptns = 0;						
+ 			/*
+ 			* Does it shadow any ns-decl?
+ 			*/
+ 			if (nsMap) {
+ 			    for (mi = nsMap; mi != topmi->next; mi = mi->next) {
+ 				if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
+ 				    (mi->shadowDepth == -1) &&
+ 				    ((ns->prefix == mi->newNs->prefix) ||
+ 				    xmlStrEqual(ns->prefix, mi->newNs->prefix))) {
+ 				    
+ 				    mi->shadowDepth = depth;
+ 				}
+ 			    }
+ 			}
+ 			/*
+ 			* Push mapping.
+ 			*/
+ 			if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi, ns, ns,
+ 			    depth) == NULL)
+ 			    goto internal_error;
+ 		    }
+ 		}
+ 		if (! adoptns)
+ 		    goto ns_end;
+ 
+ 		/* No break on purpose. */
+ 	    case XML_ATTRIBUTE_NODE:
+ 		if (cur->ns == NULL)
+ 		    goto ns_end;
+ 		if (! parnsdone) {
+ 		    if ((elem->parent) &&
+ 			((xmlNodePtr) elem->parent->doc != elem->parent)) {
+ 			if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
+ 				elem->parent) == -1)
+ 			    goto internal_error;
+ 			if (nsMap != NULL)
+ 			    topmi = nsMap->prev;
+ 		    }
+ 		    parnsdone = 1;
+ 		}
+ 		/*
+ 		* Adopt ns-references.
+ 		*/
+ 		if (nsMap != NULL) {
+ 		    /*
+ 		    * Search for a mapping.
+ 		    */
+ 		    for (mi = nsMap; mi != topmi->next; mi = mi->next) {
+ 			if ((mi->shadowDepth == -1) &&
+ 			    (cur->ns == mi->oldNs)) {
+ 
+ 			    cur->ns = mi->newNs;
+ 			    goto ns_end;
+ 			}
+ 		    }
+ 		}
+ 		/*
+ 		* Aquire a normalized ns-decl and add it to the map.
+ 		*/
+ 		if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem,
+ 			cur->ns, &ns,
+ 			&nsMap, &topmi, depth,
+ 			ancestorsOnly,
+ 			(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
+ 		    goto internal_error;
+ 		cur->ns = ns;
+ 
+ ns_end:
+ 		if ((cur->type == XML_ELEMENT_NODE) &&
+ 		    (cur->properties != NULL)) {
+ 		    /*
+ 		    * Process attributes.
+ 		    */
+ 		    cur = (xmlNodePtr) cur->properties;
+ 		    continue;
+ 		}
+ 		break;		
+ 	    default:
+ 		goto next_sibling;
+ 	}
+ 	if ((cur->type == XML_ELEMENT_NODE) &&
+ 	    (cur->children != NULL)) {
+ 	    /*
+ 	    * Process content of element-nodes only.
+ 	    */
+ 	    cur = cur->children;
+ 	    continue;
+ 	}
+ next_sibling:	
+ 	if (cur == elem)
+ 	    break;
+ 	if (cur->type == XML_ELEMENT_NODE) {
+ 	    if (nsMap != NULL) {
+ 		/*
+ 		* Pop mappings.
+ 		*/
+ 		while ((topmi->depth >= 0) && (topmi->depth >= depth))
+ 		    topmi = topmi->prev;
+ 		/*
+ 		* Unshadow.
+ 		*/
+ 		for (mi = nsMap; mi != topmi->next; mi = mi->next)
+ 		    if (mi->shadowDepth >= depth)
+ 			mi->shadowDepth = -1;
+ 	    }
+ 	    depth--;
+ 	}
+ 	if (cur->next != NULL)
+ 	    cur = cur->next;
+ 	else {
+ 	    cur = cur->parent;
+ 	    goto next_sibling;
+ 	}
+     } while (cur != NULL);
+ 
+     if (nsMap != NULL)
+ 	xmlDOMWrapNSNormFreeNsMap(nsMap);
+     return (0);
+ internal_error:
+     if (nsMap != NULL)
+ 	xmlDOMWrapNSNormFreeNsMap(nsMap);    
+     return (-1);
+ }
+ 
+ /*
+ * xmlDOMWrapAdoptBranch:
+ * @ctxt: the optional context for custom processing
+ * @sourceDoc: the optional sourceDoc
+ * @node: the element-node to start with
+ * @destDoc: the destination doc for adoption
+ * @parent: the optional new parent of @node in @destDoc
+ * @options: option flags
+ *
+ * Ensures that ns-references point to @destDoc: either to
+ * elements->nsDef entries if @destParent is given, or to
+ * @destDoc->oldNs otherwise.
+ * If @destParent is given, it ensures that the tree is namespace
+ * wellformed by creating additional 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.
+ *
+ * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
+ */
+ static int
+ xmlDOMWrapAdoptBranch(xmlFooCtxtPtr ctxt,
+ 		      xmlDocPtr sourceDoc,
+ 		      xmlNodePtr node,
+ 		      xmlDocPtr destDoc,
+ 		      xmlNodePtr destParent,
+ 		      int options ATTRIBUTE_UNUSED)
+ {
+     int ret = 0;
+     xmlNodePtr cur, curElem = NULL;
+     xmlNsMapItemPtr nsMap = NULL, topmi = NULL, mi;
+     xmlNsPtr ns;
+     int depth = -1, adoptStr = 1;
+     /* gather @parent's ns-decls. */
+     int parnsdone = 0;
+     /* @ancestorsOnly should be set per option. */
+     int ancestorsOnly = 0;
+     
+     /*
+     * Optimize string adoption for equal or none dicts.
+     */
+     if ((sourceDoc != NULL) &&
+ 	(sourceDoc->dict == destDoc->dict))
+ 	adoptStr = 0;
+     else
+ 	adoptStr = 1;
+ 
+     cur = node;
+     while (cur != NULL) {
+ 	if (cur->doc != sourceDoc) {
+ 	    /*
+ 	    * We'll assume XIncluded nodes if the doc differs.
+ 	    * TODO: Do we need to reconciliate XIncluded nodes?
+ 	    * This here skips XIncluded nodes and tries to handle
+ 	    * broken sequences.
+ 	    */
+ 	    if (cur->next == NULL)
+ 		goto leave_node;
+ 	    do {
+ 		cur = cur->next;
+ 		if ((cur->type == XML_XINCLUDE_END) ||
+ 		    (cur->doc == node->doc))
+ 		    break;
+ 	    } while (cur->next != NULL);
+ 
+ 	    if (cur->doc != node->doc)
+ 		goto leave_node;
+ 	}
+ 	cur->doc = destDoc;
+ 	switch (cur->type) {
+ 	    case XML_XINCLUDE_START:		
+ 	    case XML_XINCLUDE_END:
+ 		/*
+ 		* TODO
+ 		*/
+ 		return (-1);
+ 	    case XML_ELEMENT_NODE:   	
+ 		curElem = cur;
+ 		depth++;
+ 		/*
+ 		* Namespace declarations.
+ 		*/
+ 		if ((ctxt == NULL) && (cur->nsDef != NULL)) {
+ 		    if (! parnsdone) {
+ 			if (destParent && (ctxt == NULL)) {
+ 			    /*
+ 			    * Gather @parent's in-scope ns-decls.
+ 			    */
+ 			    if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
+ 				destParent) == -1)
+ 				goto internal_error;
+ 			    if (nsMap != NULL)
+ 				topmi = nsMap->prev;
+ 			}
+ 			parnsdone = 1;
+ 		    }
+ 		    for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
+ 			/*
+ 			* ns->prefix and ns->href seem not to be in the dict.
+ 			* XML_TREE_ADOPT_STR(ns->prefix)
+ 			* XML_TREE_ADOPT_STR(ns->href)
+ 			*/			
+ 			/*
+ 			* Does it shadow any ns-decl?
+ 			*/			
+ 			if (nsMap) {
+ 			    for (mi = nsMap; mi != topmi->next;
+ 			    mi = mi->next) {
+ 				if ((mi->depth >= XML_TREE_NSMAP_PARENT) &&
+ 				    (mi->shadowDepth == -1) &&
+ 				    ((ns->prefix == mi->newNs->prefix) ||
+ 				    xmlStrEqual(ns->prefix,
+ 				    mi->newNs->prefix))) {
+ 				    
+ 				    mi->shadowDepth = depth;
+ 				}
+ 			    }
+ 			}
+ 			/*
+ 			* Push mapping.
+ 			*/
+ 			if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
+ 			    ns, ns, depth) == NULL)
+ 			    goto internal_error;
+ 		    }
+ 		}
+ 		/* No break on purpose. */	    
+ 	    case XML_ATTRIBUTE_NODE:
+ 		
+ 		if (cur->ns == NULL)
+ 		    goto ns_end;
+ 		if (! parnsdone) {
+ 		    if (destParent && (ctxt == NULL)) {
+ 			if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
+ 			    destParent) == -1)
+ 			    goto internal_error;
+ 			if (nsMap != NULL)
+ 			    topmi = nsMap->prev;
+ 		    }
+ 		    parnsdone = 1;
+ 		}
+ 		/*
+ 		* Adopt ns-references.
+ 		*/
+ 		if (nsMap != NULL) {
+ 		    /*
+ 		    * Search for a mapping.
+ 		    */
+ 		    for (mi = nsMap; mi != topmi->next; mi = mi->next) {
+ 			if ((mi->shadowDepth == -1) &&
+ 			    (cur->ns == mi->oldNs)) {
+ 
+ 			    cur->ns = mi->newNs;
+ 			    goto ns_end;
+ 			}
+ 		    }
+ 		}
+ 		/*
+ 		* Start searching for an in-scope ns-decl.
+ 		*/		
+ 		if (ctxt != NULL) {
+ 		    /*
+ 		    * User-defined behaviour.
+ 		    */
+ #if 0
+ 		    ctxt->aquireNsDecl(ctxt, cur->ns, &ns);
+ #endif		    
+ 		    /*
+ 		    * Insert mapping if ns is available; it's the users fault
+ 		    * if not.
+ 		    */
+ 		    if (xmlDOMWrapNSNormAddNsMapItem(&nsMap, &topmi,
+ 			    ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
+ 			goto internal_error;
+ 		    cur->ns = ns;
+ 		} else {
+ 		    /*
+ 		    * Aquire a normalized ns-decl and add it to the map.
+ 		    */
+ 		    if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc,
+ 			/* ns-decls on curElem or on destDoc->oldNs */			
+ 			destParent ? curElem : NULL,
+ 			cur->ns, &ns,
+ 			&nsMap, &topmi, depth,
+ 			ancestorsOnly,
+ 			/* ns-decls must be prefixed for attributes. */
+ 			(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
+ 			goto internal_error;
+ 		    cur->ns = ns;
+ 		}
+ ns_end:
+ 		/*
+ 		* Further node properties.
+ 		* TODO: Is this all?
+ 		*/
+ 		XML_TREE_ADOPT_STR(cur->name)
+ 		if (cur->type == XML_ELEMENT_NODE) {
+ 		    cur->psvi = NULL;
+ 		    cur->line = 0;
+ 		    cur->extra = 0;
+ 		    /*
+ 		    * Walk attributes.
+ 		    */
+ 		    if (cur->properties != NULL) {
+ 			/*
+ 			* Process first attribute node.
+ 			*/
+ 			cur = (xmlNodePtr) cur->properties;
+ 			continue;
+ 		    }
+ 		} else {
+ 		    /*
+ 		    * Attributes.
+ 		    */
+ 		    if ((sourceDoc != NULL) &&
+ 			(((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
+ 			xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
+ 		    ((xmlAttrPtr) cur)->atype = 0;
+ 		    ((xmlAttrPtr) cur)->psvi = NULL;
+ 		}
+ 		break;
+ 	    case XML_TEXT_NODE:
+ 	    case XML_CDATA_SECTION_NODE:		
+ 		/*
+ 		* This puts the content in the dest dict, only if
+ 		* it was previously in the source dict.
+ 		*/
+ 		XML_TREE_ADOPT_STR_2(cur->content)		
+ 		goto leave_node;	   
+ 	    case XML_ENTITY_REF_NODE:
+ 		/*
+ 		* Remove reference to the entitity-node.
+ 		*/
+ 		cur->content = NULL;
+ 		cur->children = NULL;
+ 		cur->last = NULL;
+ 		if ((destDoc->intSubset) || (destDoc->extSubset)) {
+ 		    xmlEntityPtr ent;
+ 		    /*
+ 		    * Assign new entity-node if available.
+ 		    */
+ 		    ent = xmlGetDocEntity(destDoc, cur->name);
+ 		    if (ent != NULL) {
+ 			cur->content = ent->content;
+ 			cur->children = (xmlNodePtr) ent;
+ 			cur->last = (xmlNodePtr) ent;
+ 		    }
+ 		}
+ 		goto leave_node;
+ 	    case XML_PI_NODE:
+ 		XML_TREE_ADOPT_STR(cur->name)
+ 		XML_TREE_ADOPT_STR_2(cur->content)
+ 		break;
+ 	    case XML_COMMENT_NODE:	    
+ 		break;
+ 	    default:
+ 		goto internal_error;
+ 	}
+ 	/*
+ 	* Walk the tree.
+ 	*/
+ 	if (cur->children != NULL) {
+ 	    cur = cur->children;
+ 	    continue;
+ 	}
+ 
+ leave_node:
+ 	if (cur == node)
+ 	    break;
+ 	if ((cur->type == XML_ELEMENT_NODE) ||
+ 	    (cur->type == XML_XINCLUDE_START) ||
+ 	    (cur->type == XML_XINCLUDE_END)) {
+ 	    /*
+ 	    * TODO: Do we expect nsDefs on XML_XINCLUDE_START?
+ 	    */
+ 	    if (nsMap != NULL) {
+ 		/*
+ 		* Pop mappings.
+ 		*/
+ 		while (topmi->depth >= depth)
+ 		    topmi = topmi->prev;
+ 		/*
+ 		* Unshadow.
+ 		*/
+ 		for (mi = nsMap; mi != topmi->next; mi = mi->next)
+ 		    if (mi->shadowDepth >= depth)
+ 			mi->shadowDepth = -1;
+ 	    }
+ 	    depth--;
+ 	}
+ 	if (cur->next != NULL)
+ 	    cur = cur->next;
+ 	else {
+ 	    cur = cur->parent;
+ 	    goto leave_node;
+ 	}
+     }
+     /*
+     * Cleanup.
+     */
+     if (nsMap != NULL)
+ 	xmlDOMWrapNSNormFreeNsMap(nsMap);
+     return (ret);
+ internal_error:
+     if (nsMap != NULL)
+ 	xmlDOMWrapNSNormFreeNsMap(nsMap);
+     return (-1);
+ }
+ 
+ /*
+ * xmlDOMWrapAdoptAttr:
+ * @ctxt: the optional context for custom processing
+ * @sourceDoc: the optional source document of attr
+ * @attr: the attribute-node to be adopted
+ * @destDoc: the destination doc for adoption
+ * @destParent: the optional new parent of @attr in @destDoc
+ * @options: option flags
+ *
+ * @attr is adopted by @destDoc.
+ * Ensures that ns-references point to @destDoc: either to
+ * elements->nsDef entries if @destParent is given, or to
+ * @destDoc->oldNs otherwise.
+ *
+ * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
+ */
+ static int
+ xmlDOMWrapAdoptAttr(xmlFooCtxtPtr ctxt,
+ 		    xmlDocPtr sourceDoc,
+ 		    xmlAttrPtr attr,
+ 		    xmlDocPtr destDoc,
+ 		    xmlNodePtr destParent,
+ 		    int options ATTRIBUTE_UNUSED)
+ {
+     xmlNodePtr cur;
+     int adoptStr = 1;
+ 
+     if ((attr == NULL) || (destDoc == NULL))
+ 	return (-1);
+     
+     attr->doc = destDoc;
+     if (attr->ns != NULL) {
+ 	xmlNsPtr ns = NULL;
+ 
+ 	if (ctxt != NULL) {
+ 	    /* TODO: User defined. */
+ 	}
+ 	/* XML Namespace. */
+ 	if ((attr->ns->prefix[0] == 'x') && (attr->ns->prefix[1] == 'm') &&
+ 	    (attr->ns->prefix[2] == 'l') && (attr->ns->prefix[3] == 0)) {
+ 	    ns = xmlTreeEnsureXMLDecl(destDoc);
+ 	} else if (destParent == NULL) {
+ 	    /*
+ 	    * Store in @destDoc->oldNs.
+ 	    */
+ 	    ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix);
+ 	} else {
+ 	    /*
+ 	    * Declare on @destParent.
+ 	    */
+ 	    if (xmlSearchNsByHrefStrict(destDoc, destParent, attr->ns->href,
+ 		&ns, 1) == -1)
+ 		goto internal_error;
+ 	    if (ns == NULL) {
+ 		ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
+ 		    attr->ns->href, attr->ns->prefix, 1);
+ 	    }
+ 	}	    
+ 	if (ns == NULL)
+ 	    goto internal_error;
+ 	attr->ns = ns;
+     }   
+     
+     XML_TREE_ADOPT_STR(attr->name);    
+     attr->atype = 0;
+     attr->psvi = NULL;
+     /*
+     * Walk content.
+     */
+     if (attr->children == NULL)
+ 	return (0);
+     cur = attr->children;
+     while (cur != NULL) {
+ 	cur->doc = destDoc;
+ 	switch (cur->type) {
+ 	    case XML_TEXT_NODE:
+ 	    case XML_CDATA_SECTION_NODE:
+ 		XML_TREE_ADOPT_STR_2(cur->content)
+ 		break;	   
+ 	    case XML_ENTITY_REF_NODE:
+ 		/*
+ 		* Remove reference to the entitity-node.
+ 		*/
+ 		cur->content = NULL;
+ 		cur->children = NULL;
+ 		cur->last = NULL;
+ 		if ((destDoc->intSubset) || (destDoc->extSubset)) {
+ 		    xmlEntityPtr ent;
+ 		    /*
+ 		    * Assign new entity-node if available.
+ 		    */
+ 		    ent = xmlGetDocEntity(destDoc, cur->name);
+ 		    if (ent != NULL) {
+ 			cur->content = ent->content;
+ 			cur->children = (xmlNodePtr) ent;
+ 			cur->last = (xmlNodePtr) ent;
+ 		    }	    	    		
+ 		}
+ 		break;
+ 	    default:
+ 		break;
+ 	}
+ 	if (cur->children != NULL) {
+ 	    cur = cur->children;
+ 	    continue;
+ 	}
+ next_sibling:
+ 	if (cur == (xmlNodePtr) attr)
+ 	    break;
+ 	if (cur->next != NULL)
+ 	    cur = cur->next;
+ 	else {
+ 	    cur = cur->parent;
+ 	    goto next_sibling;
+ 	}
+     }
+     return (0);
+ internal_error:
+     return (-1);
+ }
+ 
+ /*
+ * xmlDOMWrapAdoptNode:
+ * @ctxt: the optional context for custom processing
+ * @sourceDoc: the optional sourceDoc
+ * @node: the node to start with
+ * @destDoc: the destination doc
+ * @parent: the optional new parent of @node in @destDoc
+ * @options: option flags
+ *
+ * Ensures that ns-references point to @destDoc: either to
+ * elements->nsDef entries if @destParent is given, or to
+ * @destDoc->oldNs otherwise.
+ * If @destParent is given, it ensures that the tree is namespace
+ * wellformed by creating additional 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.
+ *
+ * Returns 0 if succeeded, -1 otherwise and on API/internal errors.
+ */
+ int
+ xmlDOMWrapAdoptNode(xmlFooCtxtPtr ctxt,
+ 		    xmlDocPtr sourceDoc,
+ 		    xmlNodePtr node,
+ 		    xmlDocPtr destDoc,		    
+ 		    xmlNodePtr destParent,
+ 		    int options)
+ {    
+     if ((node == NULL) || (destDoc == NULL) ||
+ 	((destParent != NULL) && (destParent->doc != destDoc)))
+ 	return(-1);
+     /*
+     * Check node->doc sanity.
+     */    
+     if ((node->doc != NULL) && (sourceDoc != NULL) &&
+ 	(node->doc != sourceDoc)) {
+ 	/*
+ 	* Might be an XIncluded node.
+ 	*/
+ 	return (-1);
+     }
+     if (sourceDoc == NULL)
+ 	sourceDoc = node->doc;
+     if (sourceDoc == destDoc)
+ 	return (-1);
+     switch (node->type) {
+ 	case XML_ELEMENT_NODE:	    
+ 	case XML_ATTRIBUTE_NODE:
+ 	case XML_TEXT_NODE:
+ 	case XML_CDATA_SECTION_NODE:
+ 	case XML_ENTITY_REF_NODE:
+ 	case XML_PI_NODE:
+ 	case XML_COMMENT_NODE:
+ 	    break;
+ 	case XML_DOCUMENT_FRAG_NODE:
+ 	    return (2);
+ 	default:
+ 	    return (1);
+     }
+     /*
+     * Unlink only if @node was not already added to @destParent.
+     */
+     if ((node->parent != NULL) && (destParent != node->parent))
+ 	xmlUnlinkNode(node);
+ 
+     if (node->type == XML_ELEMENT_NODE) {
+ 	    return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node,
+ 		    destDoc, destParent, options));
+     } else if (node->type == XML_ATTRIBUTE_NODE) {
+ 	    return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
+ 		(xmlAttrPtr) node, destDoc, destParent, options));
+     } else {	
+ 	xmlNodePtr cur = node;
+ 	int adoptStr = 1;
+ 
+ 	cur->doc = destDoc;
+ 	/*
+ 	* Optimize string adoption.
+ 	*/
+ 	if ((sourceDoc != NULL) &&
+ 	    (sourceDoc->dict == destDoc->dict))
+ 		adoptStr = 0;
+ 	switch (node->type) {
+ 	    case XML_TEXT_NODE:	    
+ 	    case XML_CDATA_SECTION_NODE:
+ 		XML_TREE_ADOPT_STR_2(node->content)
+ 		    break;
+ 	    case XML_ENTITY_REF_NODE:
+ 		/*
+ 		* Remove reference to the entitity-node.
+ 		*/
+ 		node->content = NULL;
+ 		node->children = NULL;
+ 		node->last = NULL;
+ 		if ((destDoc->intSubset) || (destDoc->extSubset)) {
+ 		    xmlEntityPtr ent;
+ 		    /*
+ 		    * Assign new entity-node if available.
+ 		    */
+ 		    ent = xmlGetDocEntity(destDoc, node->name);
+ 		    if (ent != NULL) {
+ 			node->content = ent->content;
+ 			node->children = (xmlNodePtr) ent;
+ 			node->last = (xmlNodePtr) ent;
+ 		    }
+ 		}
+ 		XML_TREE_ADOPT_STR(node->name)
+ 		break;
+ 	    case XML_PI_NODE:
+ 		XML_TREE_ADOPT_STR(node->name)
+ 		XML_TREE_ADOPT_STR_2(node->content)
+ 		break;
+ 	    default:
+ 		break;
+ 	}
+     }	
+     return (0);
+ }
+ 
+ 
  #define bottom_tree
  #include "elfgcchack.h"
Index: include/libxml/tree.h
===================================================================
RCS file: /cvs/gnome/libxml2/include/libxml/tree.h,v
retrieving revision 1.145
diff -c -r1.145 tree.h
*** include/libxml/tree.h	2 Jan 2005 09:53:12 -0000	1.145
--- include/libxml/tree.h	22 Jun 2005 15:01:13 -0000
***************
*** 250,256 ****
      XML_ELEMENT_TYPE_ELEMENT
  } xmlElementTypeVal;
  
- 
  #ifdef __cplusplus
  }
  #endif
--- 250,255 ----
***************
*** 509,514 ****
--- 508,519 ----
      void           *psvi;	/* for type/PSVI informations */
  };
  
+ typedef struct _xmlFooCtxt xmlFooCtxt;
+ typedef xmlFooCtxt *xmlFooCtxtPtr;
+ struct _xmlFooCtxt {
+     int bar;
+ };
+ 
  /**
   * xmlChildrenNode:
   *
***************
*** 1113,1118 ****
--- 1118,1142 ----
  		xmlGetCompressMode	(void);
  XMLPUBFUN void XMLCALL		
  		xmlSetCompressMode	(int mode);
+ 
+ /*
+ * DOM-wrapper helper functions.
+ */
+ XMLPUBFUN int XMLCALL
+ 	    xmlDOMWrapReconcileNamespaces(xmlFooCtxtPtr ctxt,
+ 					 xmlNodePtr elem,
+ 					 int options);
+ XMLPUBFUN int XMLCALL
+ 	    xmlDOMWrapAdoptNode		(xmlFooCtxtPtr ctxt,
+ 					 xmlDocPtr sourceDoc,
+ 					 xmlNodePtr node,
+ 					 xmlDocPtr destDoc,		    
+ 					 xmlNodePtr destParent,
+ 					 int options);
+ XMLPUBFUN int XMLCALL
+ 	    xmlDOMWrapRemoveNode	(xmlFooCtxtPtr ctxt,
+ 					 xmlDocPtr doc,
+ 					 xmlNodePtr node);
  
  #ifdef __cplusplus
  }
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
	<xsl:output method="text"/>

	<xsl:template match="/">
		<xsl:text><![CDATA[
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
]]>
</xsl:text>
		<xsl:call-template name="serializer"/>		
		<xsl:apply-templates select="tests/test"/>
		<xsl:text>

int main(int argc, char **argv) {&#xA;</xsl:text>
		<xsl:apply-templates select="tests/test" mode="call"/>
		<xsl:text>
	printf("finished.\n");
	return (0);
}
</xsl:text>
	</xsl:template>	

	<xsl:template match="tests/test" mode="call">
		<xsl:text>	nsTest_</xsl:text>
		<xsl:value-of select="@name"/>
		<xsl:text>();&#xA;</xsl:text>
	</xsl:template>

	<xsl:template name="xml-text">
		<xsl:param name="text"/>
		<xsl:call-template name="replace-string">
			<!-- Substitute #10 for " -->	        			
	        <xsl:with-param name="from" select="'&#10;'"/>
	        <xsl:with-param name="to" select="'&quot;&#10;&quot;'"/>
			<xsl:with-param name="text">
				<xsl:call-template name="replace-string">
					<!-- Substitute " for \" -->
	        		<xsl:with-param name="from" select="'&quot;'"/>
	        		<xsl:with-param name="to" select="'\&quot;'"/>
					<xsl:with-param name="text">
						<xsl:call-template name="replace-string">
							<!-- Remove tabs. -->
			        		<xsl:with-param name="from" select="'&#9;'"/>
			        		<xsl:with-param name="to" select="''"/>
							<xsl:with-param name="text" select="$text"/>
	    				</xsl:call-template>
					</xsl:with-param>
    			</xsl:call-template>
			</xsl:with-param>
    	</xsl:call-template>
		
	</xsl:template>

	<xsl:template match="doc" mode="define">
		<xsl:text>	xmlDocPtr </xsl:text>
		<xsl:value-of select="@name"/>
		<xsl:text>;&#xA;</xsl:text>
		<xsl:text>	const char * </xsl:text>
		<xsl:value-of select="@name"/>
		<xsl:text>_str = "</xsl:text>
		<xsl:call-template name="xml-text">
	        <xsl:with-param name="text" select="."/>
    	</xsl:call-template>		
		<xsl:text>";&#xA;</xsl:text>
	</xsl:template>

	<xsl:template match="expected" mode="define">
		<xsl:text>	const char * </xsl:text>	
		<xsl:text>exp_str = "</xsl:text>
		<xsl:call-template name="xml-text">
	        <xsl:with-param name="text" select="."/>
    	</xsl:call-template>		
		<xsl:text>";&#xA;</xsl:text>
	</xsl:template>

	<xsl:template match="doc">
		<xsl:text>	</xsl:text>
		<xsl:value-of select="@name"/>
		<xsl:text> = xmlReadDoc(BAD_CAST </xsl:text>
		<xsl:value-of select="@name"/>
		<xsl:text>_str, NULL, NULL, 0);&#xA;</xsl:text>
			
		<xsl:apply-templates select="following-sibling::*[1]"/>

		<xsl:text>	xmlFreeDoc(</xsl:text>
		<xsl:value-of select="@name"/>
		<xsl:text>);&#xA;</xsl:text>
	</xsl:template>

	<xsl:template match="xpath">
	</xsl:template>

	<xsl:template match="var" mode="define">
		<xsl:text>	xmlNodePtr </xsl:text>
		<xsl:value-of select="@name"/>
		<xsl:text>;&#xA;</xsl:text>
	</xsl:template>

	<xsl:template match="var">
		<xsl:if test="xpath">
			<!-- Create XPath context. -->
			<xsl:text>	/* Selecting node "</xsl:text><xsl:value-of select="@name"/><xsl:text>". */&#xA;</xsl:text>
			<xsl:text>	xp = xmlXPathNewContext(</xsl:text>
			<xsl:value-of select="xpath/@doc"/>
			<xsl:text>);&#xA;</xsl:text>
			<!-- Register namespaces. -->
			<xsl:for-each select="xpath/reg-ns">
				<xsl:text>	xmlXPathRegisterNs(xp, BAD_CAST "</xsl:text>
				<xsl:value-of select="@prefix"/>
				<xsl:text>", BAD_CAST "</xsl:text>
				<xsl:value-of select="@ns"/>
				<xsl:text>");&#xA;</xsl:text>
			</xsl:for-each>
			<!-- Evaluate. -->
			<xsl:text>	</xsl:text>
			<xsl:value-of select="@name"/>
			<xsl:text> = nsSelectNode(xp, "</xsl:text>
			<xsl:value-of select="xpath/@select-node"/>
			<xsl:text>");&#xA;</xsl:text>
			<xsl:text>	xmlXPathFreeContext(xp);&#xA;</xsl:text>
		</xsl:if>
		<xsl:apply-templates select="following-sibling::*[1]"/>
	</xsl:template>

	<xsl:template match="reconcile-ns">
		<xsl:text>	/* Reconcile node "</xsl:text><xsl:value-of select="@ref"/><xsl:text>". */&#xA;</xsl:text>
		<xsl:text>	xmlDOMWrapReconcileNamespaces(NULL, </xsl:text>
		<xsl:value-of select="@node"/>
		<xsl:text>, 0);&#xA;</xsl:text>
		<xsl:apply-templates select="following-sibling::*[1]"/>
	</xsl:template>

	<xsl:template match="remove">
		<xsl:text>	xmlDOMWrapRemoveNode(NULL, </xsl:text>
		<xsl:value-of select="@node"/>
		<xsl:text>->doc, </xsl:text>
		<xsl:value-of select="@node"/>
		<xsl:text>);&#xA;</xsl:text>
		<xsl:apply-templates select="following-sibling::*[1]"/>
	</xsl:template>

	<xsl:template match="adopt">
		<xsl:text>	/* Adopt "</xsl:text><xsl:value-of select="@node"/><xsl:text>". */&#xA;</xsl:text>
		<xsl:text>	xmlDOMWrapAdoptNode(NULL, </xsl:text>
		<xsl:value-of select="@node"/>
		<xsl:text>->doc, </xsl:text>
		<xsl:value-of select="@node"/>
		<xsl:text>, </xsl:text>
		<xsl:value-of select="@dest-doc"/>
		<xsl:text>, </xsl:text>
		<xsl:choose>
			<xsl:when test="@dest-parent">
				<xsl:value-of select="@dest-parent"/>
			</xsl:when>
			<xsl:otherwise>
				<xsl:text>NULL</xsl:text>
			</xsl:otherwise>
		</xsl:choose>		
		<xsl:text>, 0);&#xA;</xsl:text>
		<xsl:apply-templates select="following-sibling::*[1]"/>
	</xsl:template>

	<xsl:template match="append-child">
		<xsl:text>	xmlAddChild(</xsl:text>
		<xsl:value-of select="@parent"/>
		<xsl:text>, </xsl:text>
		<xsl:value-of select="@child"/>
		<xsl:text>);&#xA;</xsl:text>
		<xsl:apply-templates select="following-sibling::*[1]"/>
	</xsl:template>

	<xsl:template match="expected">		
		<xsl:text>	/* Serialize "</xsl:text><xsl:value-of select="@doc"/><xsl:text>". */&#xA;</xsl:text>
		<xsl:text>	result_str = nsSerializeNode(xmlDocGetRootElement(</xsl:text>
		<xsl:value-of select="@doc"/>
		<xsl:text>));&#xA;</xsl:text>
		<xsl:text>	/* Compare result. */
	if (! xmlStrEqual(BAD_CAST result_str, BAD_CAST exp_str)) {
		printf("FAILED\n");
		printf("%s\n", (const char *) result_str);
		printf("- - -\n");
		printf("Expected:\n%s\n", exp_str);
		printf("= = =\n");
	}
	xmlFree(result_str);&#xA;</xsl:text>
	</xsl:template>

	<!--********
	    * TEST *
	    ********-->
	<xsl:template match="test">		
		<xsl:text>void nsTest_</xsl:text>
		<xsl:value-of select="@name"/>
		<xsl:text>(void) {
	xmlChar * result_str;
	xmlXPathContextPtr xp;
	int memory;&#xA;</xsl:text>
		<xsl:apply-templates select="*" mode="define"/>
		<xsl:text>
	memory = xmlMemUsed();
	xmlInitParser();&#xA;&#xA;</xsl:text>
		<xsl:apply-templates select="child::*[1]"/>
		<xsl:text>
	xmlCleanupParser();
	memory = xmlMemUsed() - memory;

	if (memory != 0) {		
		printf("## '%s' MEMORY leak: %d\n", "</xsl:text>
		<xsl:value-of select="@name"/>
		<xsl:text>", memory);
    }		
}
</xsl:text>	
	</xsl:template>

	<xsl:template name="serializer">
		<xsl:text>
		
xmlChar * nsSerializeNode(xmlNodePtr node) {
	xmlChar * ret;

	xmlOutputBufferPtr buf;
	buf = xmlAllocOutputBuffer(NULL);
	xmlNodeDumpOutput(buf, node->doc, node, 0, 0, NULL);
	xmlOutputBufferFlush(buf);
	ret = (xmlChar *) buf->buffer->content;
	buf->buffer->content = NULL;
	(void) xmlOutputBufferClose(buf);
	return (ret);
}

xmlNodePtr nsSelectNode(xmlXPathContextPtr xp, const char * xpath) {
	xmlXPathObjectPtr xpres;
	xmlNodePtr ret;	
		
	xpres = xmlXPathEval(BAD_CAST xpath, xp);
	ret = xpres->nodesetval->nodeTab[0];
	xmlXPathFreeObject(xpres);
	return (ret);
}

</xsl:text>
	</xsl:template>

	<xsl:template name="replace-string">
    <xsl:param name="text"/>
    <xsl:param name="from"/>
    <xsl:param name="to"/>

    <xsl:choose>
      <xsl:when test="contains($text, $from)">

	<xsl:variable name="before" select="substring-before($text, $from)"/>
	<xsl:variable name="after" select="substring-after($text, $from)"/>
	<xsl:variable name="prefix" select="concat($before, $to)"/>

	<xsl:value-of select="$before"/>
	<xsl:value-of select="$to"/>
        <xsl:call-template name="replace-string">
	  <xsl:with-param name="text" select="$after"/>
	  <xsl:with-param name="from" select="$from"/>
	  <xsl:with-param name="to" select="$to"/>
	</xsl:call-template>
      </xsl:when> 
      <xsl:otherwise>
        <xsl:value-of select="$text"/>  
      </xsl:otherwise>
    </xsl:choose>            
 </xsl:template>
		
	
</xsl:stylesheet><!-- Stylus Studio meta-information - (c)1998-2004. Sonic Software Corporation. All rights reserved.
<metaInformation>
<scenarios/><MapperInfo srcSchemaPathIsRelative="yes" srcSchemaInterpretAsXML="no" destSchemaPath="" destSchemaRoot="" destSchemaPathIsRelative="yes" destSchemaInterpretAsXML="no"/>
</metaInformation>
-->
<?xml version="1.0"?>
<tests>
	<test name="adopt_recon_default">
		
		<doc name="doc1"><![CDATA[<p1 xmlns="urn:test:AAA"><a/></p1>]]></doc>
		<doc name="doc2"><![CDATA[<p1 xmlns="urn:test:BBB"><b/></p1>]]></doc>
		<doc name="doc3"><![CDATA[<p2 xmlns="urn:test:ZZZ"/>]]></doc>
		<var name="a">
			<xpath doc="doc1" select-node="/a:p1/a:a">
				<reg-ns prefix="a" ns="urn:test:AAA"/>
			</xpath>
		</var>
		<var name="b" >
			<xpath doc="doc2" select-node="/b:p1/b:b">
				<reg-ns prefix="b" ns="urn:test:BBB"/>				
			</xpath>
		</var>
		<var name="p2">
			<xpath doc="doc3" select-node="/z:p2">
				<reg-ns prefix="z" ns="urn:test:ZZZ"/>				
			</xpath>
		</var>

		<remove node="a"/>
		<adopt dest-doc="doc3" node="a"/>
		<append-child parent="p2" child="a"/>

		<!-- This time without a previous removing. -->
		<adopt dest-doc="doc3" node="b"/>
		<append-child parent="p2" child="b"/>

		<reconcile-ns node="p2"/>
		<expected doc="doc3"><![CDATA[<p2 xmlns="urn:test:ZZZ"><a xmlns="urn:test:AAA"/><b xmlns="urn:test:BBB"/></p2>]]></expected>
	</test>

	<test name="adopt_recon">		
		<doc name="doc1"><![CDATA[<a:p1 xmlns:a="urn:test:AAA"><a:a/></a:p1>]]></doc>
		<doc name="doc2"><![CDATA[<a:p2 xmlns:a="urn:test:AAA"/>]]></doc>
		<var name="a">
			<xpath doc="doc1" select-node="/a:p1/a:a">
				<reg-ns prefix="a" ns="urn:test:AAA"/>
			</xpath>
		</var>
		<var name="p2">
			<xpath doc="doc2" select-node="/a:p2">
				<reg-ns prefix="a" ns="urn:test:AAA"/>				
			</xpath>
		</var>
		<adopt dest-doc="doc2" node="a"/>
		<append-child parent="p2" child="a"/>
		<reconcile-ns node="a"/>
		<expected doc="doc2"><![CDATA[<a:p2 xmlns:a="urn:test:AAA"><a:a/></a:p2>]]></expected>
	</test>

	<test name="adopt_recon_attr">		
		<doc name="doc1"><![CDATA[<p1 xmlns:b="urn:test:BBB" b:attr="marvin"/>]]></doc>
		<doc name="doc2"><![CDATA[<a:p2 xmlns:a="urn:test:AAA"/>]]></doc>
		<var name="attr">
			<xpath doc="doc1" select-node="/p1/@b:attr">
				<reg-ns prefix="b" ns="urn:test:BBB"/>
			</xpath>
		</var>
		<var name="p2">
			<xpath doc="doc2" select-node="/a:p2">
				<reg-ns prefix="a" ns="urn:test:AAA"/>				
			</xpath>
		</var>
		<adopt dest-doc="doc2" node="attr" />
		<append-child parent="p2" child="attr"/>
		<reconcile-ns node="p2"/>
		<expected doc="doc2"><![CDATA[<a:p2 xmlns:a="urn:test:AAA" xmlns:b="urn:test:BBB" b:attr="marvin"/>]]></expected>
	</test>

	<test name="adopt_recon_attr_2">		
	    <!-- Here we will specify a destination-parent for adoption. -->
		<doc name="doc1"><![CDATA[<p1 xmlns:b="urn:test:BBB" b:attr="marvin"/>]]></doc>
		<doc name="doc2"><![CDATA[<a:p2 xmlns:a="urn:test:AAA"/>]]></doc>
		<var name="attr">
			<xpath doc="doc1" select-node="/p1/@b:attr">
				<reg-ns prefix="b" ns="urn:test:BBB"/>
			</xpath>
		</var>
		<var name="p2">
			<xpath doc="doc2" select-node="/a:p2">
				<reg-ns prefix="a" ns="urn:test:AAA"/>				
			</xpath>
		</var>		
		<adopt dest-doc="doc2" dest-parent="p2" node="attr" />		
		<append-child parent="p2" child="attr"/>
		<reconcile-ns node="p2"/>
		<expected doc="doc2"><![CDATA[<a:p2 xmlns:a="urn:test:AAA" xmlns:b="urn:test:BBB" b:attr="marvin"/>]]></expected>
	</test>

	<test name="adopt_recon_attr_3">		
	    <!-- Conflicting ns-prefixes for the added attribute. -->
		<doc name="doc1"><![CDATA[<p1 xmlns:a="urn:test:AAA" a:attr="marvin"/>]]></doc>
		<doc name="doc2"><![CDATA[<a:p2 xmlns:a="urn:test:aaa"/>]]></doc>
		<var name="attr">
			<xpath doc="doc1" select-node="/p1/@a:attr">
				<reg-ns prefix="a" ns="urn:test:AAA"/>
			</xpath>
		</var>
		<var name="p2">
			<xpath doc="doc2" select-node="/a:p2">
				<reg-ns prefix="a" ns="urn:test:aaa"/>
			</xpath>
		</var>		
		<adopt dest-doc="doc2" node="attr" />
		<append-child parent="p2" child="attr"/>
		<reconcile-ns node="p2"/>
		<expected doc="doc2"><![CDATA[<a:p2 xmlns:a="urn:test:aaa" xmlns:a1="urn:test:AAA" a1:attr="marvin"/>]]></expected>
	</test>

	<test name="adopt_recon_attr_4">
	    <!-- Qualified attribute added to default namespaced elem. -->
		<doc name="doc1"><![CDATA[<p1 xmlns:a="urn:test:AAA" a:attr="marvin"/>]]></doc>
		<doc name="doc2"><![CDATA[<p2 xmlns="urn:test:AAA"/>]]></doc>
		<var name="attr">
			<xpath doc="doc1" select-node="/p1/@a:attr">
				<reg-ns prefix="a" ns="urn:test:AAA"/>
			</xpath>
		</var>
		<var name="p2">
			<xpath doc="doc2" select-node="/a:p2">
				<reg-ns prefix="a" ns="urn:test:AAA"/>
			</xpath>
		</var>		
		<adopt dest-doc="doc2" node="attr" />
		<append-child parent="p2" child="attr"/>
		<reconcile-ns node="p2"/>
		<expected doc="doc2"><![CDATA[<p2 xmlns="urn:test:AAA" xmlns:a="urn:test:AAA" a:attr="marvin"/>]]></expected>
	</test>

	<test name="adopt_recon_attr_5">
		<!-- Shadowed and conflicting prefix. dest-parent IS given. -->
		<doc name="doc1"><![CDATA[<p1 xmlns:a="urn:test:AAA" a:attr="marvin"/>]]></doc>
		<doc name="doc2"><![CDATA[<p2 xmlns:a="urn:test:AAA"><a:p3 xmlns:a="urn:test:ZZZ"/></p2>]]></doc>
		<var name="attr">
			<xpath doc="doc1" select-node="/p1/@a:attr">
				<reg-ns prefix="a" ns="urn:test:AAA"/>
			</xpath>
		</var>
		<var name="p3">
			<xpath doc="doc2" select-node="/p2/a:p3">
				<reg-ns prefix="a" ns="urn:test:ZZZ"/>
			</xpath>
		</var>		
		<adopt dest-doc="doc2" node="attr" dest-parent="p3"/>
		<append-child parent="p3" child="attr"/>
		<!-- Note that we don't need to reconcile here, since done during
		     adoption. -->
		<expected doc="doc2"><![CDATA[
<p2 xmlns:a="urn:test:AAA">
	<a:p3 xmlns:a="urn:test:ZZZ" xmlns:a1="urn:test:AAA" a1:attr="marvin"/>
</p2>]]></expected>
	</test>

	<test name="adopt_recon_attr_6">
		<!-- Shadowed and conflicting prefix. dest-parent NOT given. -->
		<doc name="doc1"><![CDATA[<p1 xmlns:a="urn:test:AAA" a:attr="marvin"/>]]></doc>
		<doc name="doc2"><![CDATA[<p2 xmlns:a="urn:test:AAA"><a:p3 xmlns:a="urn:test:ZZZ"/></p2>]]></doc>
		<var name="attr">
			<xpath doc="doc1" select-node="/p1/@a:attr">
				<reg-ns prefix="a" ns="urn:test:AAA"/>
			</xpath>
		</var>
		<var name="p3">
			<xpath doc="doc2" select-node="/p2/a:p3">
				<reg-ns prefix="a" ns="urn:test:ZZZ"/>
			</xpath>
		</var>		
		<adopt dest-doc="doc2" node="attr"/>
		<append-child parent="p3" child="attr"/>
		<reconcile-ns node="p3"/>
		<expected doc="doc2"><![CDATA[
<p2 xmlns:a="urn:test:AAA">
	<a:p3 xmlns:a="urn:test:ZZZ" xmlns:a1="urn:test:AAA" a1:attr="marvin"/>
</p2>]]></expected>
	</test>
	
	<test name="shadow_1">
		
		<doc name="doc"><![CDATA[
<foo xmlns:foo="urn:test:mine">
	<p xmlns:bar="urn:test:mine"/>
	<a1>
		<a2 xmlns:bar="urn:test:OTHER">
			<foo:a3/>
		</a2>
	</a1>
</foo>
]]></doc>
		<var name="a1">
			<xpath doc="doc" select-node="/foo/a1"/>
		</var>
		<var name="p" >
			<xpath doc="doc" select-node="/foo/p"/>
		</var>
		<remove node="a1"/>
		<append-child parent="p" child="a1"/>
		<reconcile-ns node="a1"/>		
		<expected doc="doc"><![CDATA[
<foo xmlns:foo="urn:test:mine">
	<p xmlns:bar="urn:test:mine">
		<a1>
			<a2 xmlns:bar="urn:test:OTHER">
				<foo:a3/>
			</a2>
		</a1>
	</p>
</foo>
]]></expected>
	</test>

	<test name="norm_1">
		
		<doc name="doc"><![CDATA[
<foo>
	<p1 xmlns:a="urn:test:A" xmlns:b="urn:test:B" xmlns:c="urn:test:C">
		<a:a>
			<b:b a:attr="dont" c:attr="panic"/>
		</a:a>
	</p1>
	<p2/>
</foo>
]]></doc>
		<var name="a">
			<xpath doc="doc" select-node="/foo/p1/a:a">
				<reg-ns prefix="a" ns="urn:test:A"/>
			</xpath>
		</var>
		<var name="p2" >
			<xpath doc="doc" select-node="/foo/p2"/>
		</var>
		<remove node="a"/>
		<append-child parent="p2" child="a"/>
		<reconcile-ns node="a"/>		
		<expected doc="doc"><![CDATA[
<foo>
	<p1 xmlns:a="urn:test:A" xmlns:b="urn:test:B" xmlns:c="urn:test:C"/>		
	<p2>
		<a:a xmlns:a="urn:test:A">
			<b:b xmlns:b="urn:test:B" xmlns:c="urn:test:C" a:attr="dont" c:attr="panic"/>
		</a:a>
	</p2>
</foo>
]]></expected>
	</test>
</tests>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]