- Lots of improvements, too long to list here
- Push mode for the XML parser (HTML to come)
- XML shell like interface for debug
- improvements on XPath and validation
Daniel
diff --git a/tree.c b/tree.c
index 3242aec..c6685ea 100644
--- a/tree.c
+++ b/tree.c
@@ -2498,6 +2498,7 @@
 		return(xmlNodeListGetString(NULL, attr->val, 1));
 	    break;
 	}
+        case XML_COMMENT_NODE:
         case XML_PI_NODE:
 	    if (cur->content != NULL)
 #ifndef XML_USE_BUFFER_CONTENT
@@ -2507,8 +2508,12 @@
 #endif
 	    return(NULL);
         case XML_ENTITY_REF_NODE:
+	    /*
+	     * Locate the entity, and get it's content
+	     * @@@
+	     */
+            return(NULL);
         case XML_ENTITY_NODE:
-        case XML_COMMENT_NODE:
         case XML_DOCUMENT_NODE:
         case XML_HTML_DOCUMENT_NODE:
         case XML_DOCUMENT_TYPE_NODE:
@@ -2858,18 +2863,6 @@
 	}
 	node = node->parent;
     }
-#if 0    
-    /* Removed support for old namespaces */
-    if (doc != NULL) {
-        cur = doc->oldNs;
-	while (cur != NULL) {
-	    if ((cur->prefix != NULL) && (nameSpace != NULL) &&
-	        (!xmlStrcmp(cur->prefix, nameSpace)))
-		return(cur);
-	    cur = cur->next;
-	}
-    }
-#endif    
     return(NULL);
 }
 
@@ -2886,31 +2879,283 @@
 xmlNsPtr
 xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
     xmlNsPtr cur;
+    xmlNodePtr orig = node;
 
     if ((node == NULL) || (href == NULL)) return(NULL);
     while (node != NULL) {
 	cur = node->nsDef;
 	while (cur != NULL) {
 	    if ((cur->href != NULL) && (href != NULL) &&
-	        (!xmlStrcmp(cur->href, href)))
+	        (!xmlStrcmp(cur->href, href))) {
+		/*
+		 * Check that the prefix is not shadowed between orig and node
+		 */
+		xmlNodePtr check = orig;
+		xmlNsPtr tst;
+
+		while (check != node) {
+		    tst = check->nsDef;
+		    while (tst != NULL) {
+			if ((tst->prefix == NULL) && (cur->prefix == NULL))
+	                    goto shadowed;
+			if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
+			    (!xmlStrcmp(tst->prefix, cur->prefix)))
+	                    goto shadowed;
+		        tst = tst->next;
+		    }
+		}
 		return(cur);
+	    }
+shadowed:		    
 	    cur = cur->next;
 	}
 	node = node->parent;
     }
-#if 0    
-    /* Removed support for old namespaces */
-    if (doc != NULL) {
-        cur = doc->oldNs;
-	while (cur != NULL) {
-	    if ((cur->href != NULL) && (href != NULL) &&
-	        (!xmlStrcmp(cur->href, href)))
-		return(cur);
-	    cur = cur->next;
+    return(NULL);
+}
+
+/**
+ * xmlNewReconciliedNs
+ * @doc:  the document
+ * @tree:  a node expected to hold the new namespace
+ * @ns:  the original namespace
+ *
+ * This function tries to locate a namespace definition in a tree
+ * ancestors, or create a new namespace definition node similar to
+ * @ns trying to reuse the same prefix. However if the given prefix is
+ * null (default namespace) or reused within the subtree defined by
+ * @tree or on one of its ancestors then a new prefix is generated.
+ * Returns the (new) namespace definition or NULL in case of error
+ */
+xmlNsPtr
+xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
+    xmlNsPtr def;
+    xmlChar prefix[50];
+    int counter = 1;
+
+    if (tree == NULL) {
+#ifdef DEBUG_TREE
+        fprintf(stderr, "xmlNewReconciliedNs : tree == NULL\n");
+#endif
+	return(NULL);
+    }
+    if (ns == NULL) {
+#ifdef DEBUG_TREE
+        fprintf(stderr, "xmlNewReconciliedNs : ns == NULL\n");
+#endif
+	return(NULL);
+    }
+    /*
+     * Search an existing namespace definition inherited.
+     */
+    def = xmlSearchNsByHref(doc, tree, ns->href);
+    if (def != NULL)
+        return(def);
+
+    /*
+     * Find a close prefix which is not already in use.
+     * Let's strip namespace prefixes longer than 20 chars !
+     */
+    sprintf((char *) prefix, "%.20s", ns->prefix);
+    def = xmlSearchNs(doc, tree, prefix);
+    while (def != NULL) {
+        if (counter > 1000) return(NULL);
+        sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
+	def = xmlSearchNs(doc, tree, prefix);
+    }
+
+    /*
+     * Ok, now we are ready to create a new one.
+     */
+    def = xmlNewNs(tree, ns->href, prefix);
+    return(def);
+}
+
+/**
+ * xmlReconciliateNs
+ * @doc:  the document
+ * @tree:  a node defining the subtree to reconciliate
+ *
+ * This function checks that all the namespaces declared within the given
+ * tree are properly declared. This is needed for example after Copy or Cut
+ * and then paste operations. The subtree may still hold pointers to
+ * namespace declarations outside the subtree or invalid/masked. As much
+ * as possible the function try tu reuse the existing namespaces found in
+ * the new environment. If not possible the new namespaces are redeclared
+ * on @tree at the top of the given subtree.
+ * Returns the number of namespace declarations created or -1 in case of error.
+ */
+int
+xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
+    xmlNsPtr *oldNs = NULL;
+    xmlNsPtr *newNs = NULL;
+    int sizeCache = 0;
+    int nbCache = 0;
+
+    xmlNsPtr n;
+    xmlNodePtr node = tree;
+    xmlAttrPtr attr;
+    int ret = 0, i;
+
+    while (node != NULL) {
+        /*
+	 * Reconciliate the node namespace
+	 */
+	if (node->ns != NULL) {
+	    /*
+	     * initialize the cache if needed
+	     */
+	    if (sizeCache == 0) {
+		sizeCache = 10;
+		oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
+					       sizeof(xmlNsPtr));
+		if (oldNs == NULL) {
+		    fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
+		    return(-1);
+		}
+		newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
+					       sizeof(xmlNsPtr));
+		if (newNs == NULL) {
+		    fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
+		    xmlFree(oldNs);
+		    return(-1);
+		}
+	    }
+	    for (i = 0;i < nbCache;i++) {
+	        if (oldNs[i] == node->ns) {
+		    node->ns = newNs[i];
+		    break;
+		}
+	    }
+	    if (i == nbCache) {
+	        /*
+		 * Ok we need to recreate a new namespace definition
+		 */
+		n = xmlNewReconciliedNs(doc, tree, node->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) {
+			    fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
+			    xmlFree(newNs);
+			    return(-1);
+			}
+			newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
+			                               sizeof(xmlNsPtr));
+		        if (newNs == NULL) {
+			    fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
+			    xmlFree(oldNs);
+			    return(-1);
+			}
+		    }
+		    newNs[nbCache] = n;
+		    oldNs[nbCache++] = node->ns;
+		    node->ns = n;
+                }
+	    }
+	}
+	/*
+	 * 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) {
+			fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
+			return(-1);
+		    }
+		    newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
+						   sizeof(xmlNsPtr));
+		    if (newNs == NULL) {
+			fprintf(stderr, "xmlReconciliateNs : memory pbm\n");
+			xmlFree(oldNs);
+			return(-1);
+		    }
+		}
+		for (i = 0;i < nbCache;i++) {
+		    if (oldNs[i] == attr->ns) {
+			node->ns = newNs[i];
+			break;
+		    }
+		}
+		if (i == nbCache) {
+		    /*
+		     * Ok we need to recreate a new namespace definition
+		     */
+		    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) {
+				fprintf(stderr,
+				        "xmlReconciliateNs : memory pbm\n");
+				xmlFree(newNs);
+				return(-1);
+			    }
+			    newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
+							   sizeof(xmlNsPtr));
+			    if (newNs == NULL) {
+				fprintf(stderr,
+				        "xmlReconciliateNs : memory pbm\n");
+				xmlFree(oldNs);
+				return(-1);
+			    }
+			}
+			newNs[nbCache] = n;
+			oldNs[nbCache++] = attr->ns;
+			attr->ns = n;
+		    }
+		}
+	    }
+	    attr = attr->next;
+	}
+
+	/*
+	 * Browse the full subtree, deep first
+	 */
+        if (node->childs != NULL) {
+	    /* deep first */
+	    node = node->childs;
+	} else if ((node != tree) && (node->next != NULL)) {
+	    /* then siblings */
+	    node = node->next;
+	} else if (node != tree) {
+	    /* go up to parents->next if needed */
+	    while (node != tree) {
+	        if (node->parent != NULL)
+		    node = node->parent;
+		if ((node != tree) && (node->next != NULL)) {
+		    node = node->next;
+		    break;
+		}
+		if (node->parent == NULL) {
+		    node = NULL;
+		    break;
+		}
+	    }
+	    /* exit condition */
+	    if (node == tree) 
+	        node = NULL;
 	}
     }
-#endif    
-    return(NULL);
+    return(ret);
 }
 
 /**
@@ -3095,8 +3340,9 @@
 xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
     if (node == NULL) return;
 
-    if (node->type != XML_TEXT_NODE) {
-	fprintf(stderr, "xmlTextConcat: node is not text\n");
+    if ((node->type != XML_TEXT_NODE) &&
+        (node->type != XML_CDATA_SECTION_NODE)) {
+	fprintf(stderr, "xmlTextConcat: node is not text nor cdata\n");
         return;
     }
 #ifndef XML_USE_BUFFER_CONTENT
@@ -3376,7 +3622,11 @@
     if (len == 0) return;
 
     /* CJN What's this for??? */
-    l = xmlStrlen(str);
+    if (len < 0)
+        l = xmlStrlen(str);
+    else 
+	for (l = 0;l < len;l++)
+	    if (str[l] == 0) break;
     if (l < len){  len = l; printf("xmlBufferAdd bad length\n"); }
 
     /* CJN 11.18.99 okay, now I'm using the length */
@@ -3676,6 +3926,9 @@
 static void
 xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
             int format);
+void
+htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
+
 /**
  * xmlNodeListDump:
  * @buf:  the XML buffer output
@@ -3851,6 +4104,40 @@
 }
 
 /**
+ * xmlElemDump:
+ * @buf:  the XML buffer output
+ * @doc:  the document
+ * @cur:  the current node
+ *
+ * Dump an XML/HTML node, recursive behaviour,children are printed too.
+ */
+void
+xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
+    xmlBufferPtr buf;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        fprintf(stderr, "xmlElemDump : cur == NULL\n");
+#endif
+	return;
+    }
+    if (doc == NULL) {
+#ifdef DEBUG_TREE
+        fprintf(stderr, "xmlElemDump : doc == NULL\n");
+#endif
+    }
+    buf = xmlBufferCreate();
+    if (buf == NULL) return;
+    if ((doc != NULL) && 
+        (doc->type == XML_HTML_DOCUMENT_NODE)) {
+        htmlNodeDump(buf, doc, cur);
+    } else
+        xmlNodeDump(buf, doc, cur, 0, 1);
+    xmlBufferDump(f, buf);
+    xmlBufferFree(buf);
+}
+
+/**
  * xmlDocContentDump:
  * @buf:  the XML buffer output
  * @cur:  the document
@@ -3937,7 +4224,7 @@
  * Returns 0 (uncompressed) to 9 (max compression)
  */
 int
- xmlGetDocCompressMode (xmlDocPtr doc) {
+xmlGetDocCompressMode (xmlDocPtr doc) {
     if (doc == NULL) return(-1);
     return(doc->compression);
 }