XInclude and other stuff while travelling. Contributed patches:
- tree.[ch] xinclude.[ch] xmllint.c configure.in valid.c
  debugXML.c xmlversion.h.in: Started adding XInclude support,
  this is a new xmllint option
- tree.c xpath.c: applied TOM patches for XPath
- xpointer.c: fixed a couple of errors.
- uri.c: added an escaping function needed for xinclude
- testXPath.c hash.c HTMLtree.c: minor cleanups raised by
  new warning from RH70 gcc's version
Daniel
diff --git a/ChangeLog b/ChangeLog
index 44038b0..05507ac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+Mon Nov  6 17:22:46 CET 2000 Daniel Veillard <Daniel.Veillard@w3.org>
+
+	* tree.[ch] xinclude.[ch] xmllint.c configure.in valid.c
+	  debugXML.c xmlversion.h.in: Started adding XInclude support,
+	  this is a new xmllint option
+	* tree.c xpath.c: applied TOM patches for XPath
+	* xpointer.c: fixed a couple of errors.
+	* uri.c: added an escaping function needed for xinclude
+	* testXPath.c hash.c HTMLtree.c: minor cleanups raised by
+	  new warning from RH70 gcc's version
+
 Tue Oct 31 14:14:13 CET 2000 Daniel Veillard <Daniel.Veillard@w3.org>
 
 	* HTMLparser.c: fixed loop on invalid char in scripts
diff --git a/HTMLtree.c b/HTMLtree.c
index 0a259c5..82687ac 100644
--- a/HTMLtree.c
+++ b/HTMLtree.c
@@ -818,7 +818,8 @@
 #ifndef XML_USE_BUFFER_CONTENT
 	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
 #else
-	    xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
+	    xmlOutputBufferWriteString(buf, (const char *)
+		                       xmlBufferContent(cur->content));
 #endif
 	    xmlOutputBufferWriteString(buf, "-->");
 	}
@@ -835,7 +836,8 @@
 #ifndef XML_USE_BUFFER_CONTENT
 	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
 #else
-	    xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
+	    xmlOutputBufferWriteString(buf, (const char *)
+		                       xmlBufferContent(cur->content));
 #endif
 	}
 	return;
diff --git a/Makefile.am b/Makefile.am
index e8cd50e..56aa3ff 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -34,6 +34,7 @@
 		debugXML.c \
 		xpath.c \
 		xpointer.c \
+		xinclude.c \
 		nanohttp.c \
 		nanoftp.c
 
diff --git a/configure.in b/configure.in
index df3b7e3..dde419b 100644
--- a/configure.in
+++ b/configure.in
@@ -286,6 +286,19 @@
 AC_SUBST(WITH_XPTR)
 AC_SUBST(XPTR_OBJ)
 
+AC_ARG_WITH(xinclude, [  --with-xinclude         Add the XInclude support (on)])
+if test "$with_xinclude" = "no" ; then
+    echo Disabling XInclude support
+    WITH_XINCLUDE=0
+    XINCLUDE_OBJ=
+    with_xinclude="no"
+else    
+    WITH_XINCLUDE=1
+    XINCLUDE_OBJ=xinclude.o
+fi
+AC_SUBST(WITH_XINCLUDE)
+AC_SUBST(XINCLUDE_OBJ)
+
 AC_ARG_WITH(iconv, [  --with-iconv            Add the ICONV support (on)])
 if test "$with_iconv" = "no" ; then
     echo Disabling ICONV support
diff --git a/debugXML.c b/debugXML.c
index 4a1ce5b..9764885 100644
--- a/debugXML.c
+++ b/debugXML.c
@@ -559,6 +559,7 @@
 	    fprintf(output, "DOCUMENT_FRAG\n");
 	    break;
 	case XML_NOTATION_NODE:
+	    fprintf(output, shift);
 	    fprintf(output, "NOTATION\n");
 	    break;
 	case XML_DTD_NODE:
@@ -576,6 +577,14 @@
         case XML_NAMESPACE_DECL:
 	    xmlDebugDumpNamespace(output, (xmlNsPtr) node, depth);
 	    return;
+        case XML_XINCLUDE_START:
+	    fprintf(output, shift);
+	    fprintf(output, "INCLUDE START\n");
+	    return;
+        case XML_XINCLUDE_END:
+	    fprintf(output, shift);
+	    fprintf(output, "INCLUDE END\n");
+	    return;
 	default:
 	    fprintf(output, shift);
 	    fprintf(output, "NODE_%d !!!\n", node->type);
@@ -917,6 +926,8 @@
         case XML_ATTRIBUTE_DECL:
         case XML_ENTITY_DECL:
 	case XML_NAMESPACE_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
 	    ret = 1;
 	    break;
     }
diff --git a/hash.c b/hash.c
index a5c2770..24e524c 100644
--- a/hash.c
+++ b/hash.c
@@ -17,6 +17,7 @@
  * Author: bjorn.reese@systematic.dk
  */
 
+#include <string.h>
 #include <libxml/hash.h>
 #include <libxml/xmlmemory.h>
 #include <libxml/parser.h>
diff --git a/include/libxml/tree.h b/include/libxml/tree.h
index 8c4f708..2168d4f 100644
--- a/include/libxml/tree.h
+++ b/include/libxml/tree.h
@@ -41,9 +41,11 @@
     XML_ELEMENT_DECL=		15,
     XML_ATTRIBUTE_DECL=		16,
     XML_ENTITY_DECL=		17,
-    XML_NAMESPACE_DECL=		18
+    XML_NAMESPACE_DECL=		18,
+    XML_XINCLUDE_START=		19,
+    XML_XINCLUDE_END=		20
 #ifdef LIBXML_SGML_ENABLED
-   ,XML_SGML_DOCUMENT_NODE=	19
+   ,XML_SGML_DOCUMENT_NODE=	21
 #endif
 } xmlElementType;
 
diff --git a/include/libxml/uri.h b/include/libxml/uri.h
index 705e385..e7aeda4 100644
--- a/include/libxml/uri.h
+++ b/include/libxml/uri.h
@@ -52,6 +52,7 @@
 					 int len,
 					 char *target);
 int		xmlNormalizeURIPath	(char *path);
+xmlChar *	xmlURIEscape		(const xmlChar *str);
 void		xmlFreeURI		(xmlURIPtr uri);
 
 #ifdef __cplusplus
diff --git a/include/libxml/xinclude.h b/include/libxml/xinclude.h
new file mode 100644
index 0000000..eca4588
--- /dev/null
+++ b/include/libxml/xinclude.h
@@ -0,0 +1,26 @@
+/*
+ * xinclude.c : API to handle XInclude processing
+ *
+ * World Wide Web Consortium Working Draft 26 October 2000
+ * http://www.w3.org/TR/2000/WD-xinclude-20001026
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_XINCLUDE_H__
+#define __XML_XINCLUDE_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int	xmlXIncludeProcess	(xmlDocPtr doc);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_XINCLUDE_H__ */
diff --git a/include/libxml/xmlversion.h.in b/include/libxml/xmlversion.h.in
index 01b1ea1..4d21762 100644
--- a/include/libxml/xmlversion.h.in
+++ b/include/libxml/xmlversion.h.in
@@ -78,6 +78,15 @@
 #endif
 
 /*
+ * Whether XInclude is configured in
+ */
+#if @WITH_XINCLUDE@
+#define LIBXML_XINCLUDE_ENABLED
+#else
+#define LIBXML_XINCLUDE_DISABLED
+#endif
+
+/*
  * Whether iconv support is available
  */
 #if @WITH_ICONV@
diff --git a/testXPath.c b/testXPath.c
index be862ca..bca7173 100644
--- a/testXPath.c
+++ b/testXPath.c
@@ -41,6 +41,7 @@
 #include <libxml/debugXML.h>
 #include <libxml/xmlmemory.h>
 #include <libxml/parserInternals.h>
+#include <libxml/xpathInternals.h>
 #include <libxml/xmlerror.h>
 #if defined(LIBXML_XPTR_ENABLED)
 #include <libxml/xpointer.h>
diff --git a/tree.c b/tree.c
index ff7d768..5fd26b5 100644
--- a/tree.c
+++ b/tree.c
@@ -45,12 +45,16 @@
 #define IS_BLANK(c)							\
   (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
 
-#define UPDATE_LAST_CHILD(n) if ((n) != NULL) {				\
+#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) {		\
     xmlNodePtr ulccur = (n)->children;					\
     if (ulccur == NULL) {						\
         (n)->last = NULL;						\
     } else {								\
-        while (ulccur->next != NULL) ulccur = ulccur->next;		\
+        while (ulccur->next != NULL) {					\
+	       	ulccur->parent = (n);					\
+		ulccur = ulccur->next;					\
+	}								\
+	ulccur->parent = (n);						\
 	(n)->last = ulccur;						\
 }}
 
@@ -892,6 +896,7 @@
 
 	buffer = xmlEncodeEntitiesReentrant(node->doc, value);
 	cur->children = xmlStringGetNodeList(node->doc, buffer);
+	cur->last = NULL;
 	tmp = cur->children;
 	while (tmp != NULL) {
 	    tmp->parent = (xmlNodePtr) cur;
@@ -965,6 +970,7 @@
 
 	buffer = xmlEncodeEntitiesReentrant(node->doc, value);
 	cur->children = xmlStringGetNodeList(node->doc, buffer);
+	cur->last = NULL;
 	tmp = cur->children;
 	while (tmp != NULL) {
 	    tmp->parent = (xmlNodePtr) cur;
@@ -1027,8 +1033,20 @@
 
     cur->name = xmlStrdup(name);
     cur->doc = doc; 
-    if (value != NULL)
+    if (value != NULL) {
+	xmlNodePtr tmp;
+
 	cur->children = xmlStringGetNodeList(doc, value);
+	cur->last = NULL;
+
+	tmp = cur->children;
+	while (tmp != NULL) {
+	    tmp->parent = (xmlNodePtr) cur;
+	    if (tmp->next == NULL)
+		cur->last = tmp;
+	    tmp = tmp->next;
+	}
+    }
     return(cur);
 }
 
@@ -1239,7 +1257,7 @@
         cur->doc = doc;
 	if (content != NULL) {
 	    cur->children = xmlStringGetNodeList(doc, content);
-	    UPDATE_LAST_CHILD(cur)
+	    UPDATE_LAST_CHILD_AND_PARENT(cur)
 	}
     }
     return(cur);
@@ -1268,7 +1286,7 @@
         cur->doc = doc;
 	if (content != NULL) {
 	    cur->children = xmlNewDocText(doc, content);
-	    UPDATE_LAST_CHILD(cur)
+	    UPDATE_LAST_CHILD_AND_PARENT(cur)
 	}
     }
     return(cur);
@@ -1491,7 +1509,13 @@
 	if (ent->content != NULL)
 	    xmlBufferAdd(cur->content, ent->content, -1);
 #endif
+	/*
+	 * The parent pointer in entity is a Dtd pointer and thus is NOT
+	 * updated.  Not sure if this is 100% correct.
+	 *  -George
+	 */
 	cur->children = (xmlNodePtr) ent;
+	cur->last = (xmlNodePtr) ent;
     }
     return(cur);
 }
@@ -1662,6 +1686,47 @@
     return(cur);
 }
 
+/**
+ * xmlSetTreeDoc:
+ * @tree:  the top element
+ * @doc:  the document
+ *
+ * update all nodes under the tree to point to the right document
+ */
+void
+xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
+    if (tree == NULL)
+	return;
+    if (tree->type == XML_ENTITY_DECL)
+	return;
+    if (tree->doc != doc) {
+	if (tree->children != NULL)
+	    xmlSetListDoc(tree->children, doc);
+	tree->doc = doc;
+    }
+}
+
+/**
+ * xmlSetListDoc:
+ * @tree:  the first element
+ * @doc:  the document
+ *
+ * update all nodes in the list to point to the right document
+ */
+void
+xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
+    xmlNodePtr cur;
+
+    if (list == NULL)
+	return;
+    cur = list;
+    while (cur != NULL) {
+	if (cur->doc != doc)
+	    xmlSetTreeDoc(cur, doc);
+	cur = cur->next;
+    }
+}
+
 
 /**
  * xmlNewChild:
@@ -1779,7 +1844,8 @@
 	    xmlNodeSetContent(cur->next, tmp);
 	    xmlFree(tmp);
 #else
-	    xmlBufferAddHead(cur->next, xmlBufferContent(elem->content),
+	    xmlBufferAddHead(cur->next->content,
+		             xmlBufferContent(elem->content),
 			     xmlBufferLength(elem->content));
 #endif
 	    xmlFreeNode(elem);
@@ -1787,7 +1853,9 @@
 	}
     }
 
-    elem->doc = cur->doc;
+    if (elem->doc != cur->doc) {
+	xmlSetTreeDoc(elem, cur->doc);
+    }
     elem->parent = cur->parent;
     elem->prev = cur;
     elem->next = cur->next;
@@ -1857,7 +1925,9 @@
 	}
     }
 
-    elem->doc = cur->doc;
+    if (elem->doc != cur->doc) {
+	xmlSetTreeDoc(elem, cur->doc);
+    }
     elem->parent = cur->parent;
     elem->next = cur;
     elem->prev = cur->prev;
@@ -1926,9 +1996,9 @@
 	return(cur);
     }
 
-    if (elem->doc == NULL)
-	elem->doc = cur->doc; /* the parent may not be linked to a doc ! */
-
+    if (elem->doc != cur->doc) {
+	xmlSetTreeDoc(elem, cur->doc);
+    }
     parent = cur->parent;
     elem->prev = cur;
     elem->next = NULL;
@@ -2011,7 +2081,9 @@
     }
     while (cur->next != NULL) {
 	cur->parent = parent;
-	cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
+	if (cur->doc != parent->doc) {
+	    xmlSetTreeDoc(cur, parent->doc);
+	}
         cur = cur->next;
     }
     cur->parent = parent;
@@ -2090,7 +2162,9 @@
      * add the new element at the end of the children list.
      */
     cur->parent = parent;
-    cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
+    if (cur->doc != parent->doc) {
+	xmlSetTreeDoc(cur, parent->doc);
+    }
 
     /*
      * Handle the case where parent->content != NULL, in that case it will
@@ -2110,7 +2184,7 @@
 	    if (text->next != NULL)
 		text->next->prev = text;
 	    parent->children = text;
-	    UPDATE_LAST_CHILD(parent)
+	    UPDATE_LAST_CHILD_AND_PARENT(parent)
 #ifndef XML_USE_BUFFER_CONTENT
 	    xmlFree(parent->content);
 #else
@@ -2264,6 +2338,9 @@
 	xmlUnlinkNode(old);
 	return(old);
     }
+    if (cur == old) {
+	return(old);
+    }
     xmlUnlinkNode(cur);
     cur->doc = old->doc;
     cur->parent = old->parent;
@@ -2374,8 +2451,19 @@
     } else
         ret->ns = NULL;
 
-    if (cur->children != NULL)
+    if (cur->children != NULL) {
+	xmlNodePtr tmp;
+
 	ret->children = xmlCopyNodeList(cur->children);
+	ret->last = NULL;
+	tmp = ret->children;
+	while (tmp != NULL) {
+	    tmp->parent = (xmlNodePtr)ret;
+	    if (tmp->next == NULL)
+	        ret->last = tmp;
+	    tmp = tmp->next;
+	}
+    }
     return(ret);
 }
 
@@ -2494,7 +2582,7 @@
         ret->properties = xmlCopyPropList(ret, node->properties);
     if (node->children != NULL)
         ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
-    UPDATE_LAST_CHILD(ret)
+    UPDATE_LAST_CHILD_AND_PARENT(ret)
     return(ret);
 }
 
@@ -2633,9 +2721,18 @@
         ret->intSubset = xmlCopyDtd(doc->intSubset);
     if (doc->oldNs != NULL)
         ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
-    if (doc->children != NULL)
+    if (doc->children != NULL) {
+	xmlNodePtr tmp;
         ret->children = xmlStaticCopyNodeList(doc->children, ret,
 		                              (xmlNodePtr)ret);
+	ret->last = NULL;
+	tmp = ret->children;
+	while (tmp != NULL) {
+	    if (tmp->next == NULL)
+	        ret->last = tmp;
+	    tmp = tmp->next;
+	}
+    }
     return(ret);
 }
 
@@ -2692,6 +2789,7 @@
     if (old == NULL) {
 	if (doc->children == NULL) {
 	    doc->children = root;
+	    doc->last = root;
 	} else {
 	    xmlAddSibling(doc->children, root);
 	}
@@ -2732,6 +2830,8 @@
 #ifdef LIBXML_SGML_ENABLED
 	case XML_SGML_DOCUMENT_NODE:
 #endif
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
 	    return;
         case XML_ELEMENT_NODE:
         case XML_ATTRIBUTE_NODE:
@@ -2792,6 +2892,8 @@
         case XML_ENTITY_REF_NODE:
         case XML_ENTITY_NODE:
 	case XML_NAMESPACE_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
 #ifdef LIBXML_SGML_ENABLED
 	case XML_SGML_DOCUMENT_NODE:
 #endif
@@ -2863,6 +2965,8 @@
         case XML_NOTATION_NODE:
         case XML_HTML_DOCUMENT_NODE:
 	case XML_NAMESPACE_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
 #ifdef LIBXML_SGML_ENABLED
 	case XML_SGML_DOCUMENT_NODE:
 #endif
@@ -2911,6 +3015,8 @@
         case XML_ENTITY_REF_NODE:
         case XML_ENTITY_NODE:
 	case XML_NAMESPACE_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
 #ifdef LIBXML_SGML_ENABLED
 	case XML_SGML_DOCUMENT_NODE:
 #endif
@@ -2923,12 +3029,46 @@
 }
 
 /**
+ * xmlDocumentGetBase:
+ * @doc:  the document
+ *
+ * Searches for the Document BASE URL. The code should work on both XML
+ * and HTML document.
+ * It returns the base as defined in RFC 2396 section
+ * 5.1.3. Base URI from the Retrieval URI
+ * However it does not return the computed base (5.1.1 and 5.1.2), use
+ * xmlNodeGetBase() for this
+ *
+ * Returns a pointer to the base URL, or NULL if not found
+ *     It's up to the caller to free the memory.
+ */
+xmlChar *
+xmlDocumentGetBase(xmlDocPtr doc) {
+    if (doc == NULL)
+        return(NULL);
+    if (doc->type == XML_HTML_DOCUMENT_NODE) {
+	if (doc->URL != NULL)
+	    return(xmlStrdup(doc->URL));
+	return(NULL);
+    }
+    if (doc->URL != NULL)
+	return(xmlStrdup(doc->URL));
+    return(NULL);
+}
+
+/**
  * xmlNodeGetBase:
  * @doc:  the document the node pertains to
  * @cur:  the node being checked
  *
  * Searches for the BASE URL. The code should work on both XML
  * and HTML document even if base mechanisms are completely different.
+ * It returns the base as defined in RFC 2396 sections
+ * 5.1.1. Base URI within Document Content
+ * and
+ * 5.1.2. Base URI from the Encapsulating Entity
+ * However it does not return the document base (5.1.3), use
+ * xmlDocumentGetBase() for this
  *
  * Returns a pointer to the base URL, or NULL if not found
  *     It's up to the caller to free the memory.
@@ -2943,9 +3083,6 @@
     if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
         cur = doc->children;
 	while ((cur != NULL) && (cur->name != NULL)) {
-	    if (cur->type == XML_ENTITY_DECL) {
-		/* TODO: we are crossing entity boundaries */
-	    }
 	    if (cur->type != XML_ELEMENT_NODE) {
 	        cur = cur->next;
 		continue;
@@ -2963,18 +3100,18 @@
 	    }
 	    cur = cur->next;
 	}
-	if ((doc != NULL) && (doc->URL != NULL))
-	    return(xmlStrdup(doc->URL));
 	return(NULL);
     }
     while (cur != NULL) {
+	if (cur->type == XML_ENTITY_DECL) {
+	    xmlEntityPtr ent = (xmlEntityPtr) cur;
+	    return(xmlStrdup(ent->URI));
+	}
         base = xmlGetProp(cur, BAD_CAST "xml:base");
 	if (base != NULL)
 	    return(base);
 	cur = cur->parent;
     }
-    if ((doc != NULL) && (doc->URL != NULL))
-	return(xmlStrdup(doc->URL));
     return(NULL);
 }
  
@@ -3026,13 +3163,14 @@
         case XML_DOCUMENT_TYPE_NODE:
         case XML_NOTATION_NODE:
         case XML_DTD_NODE:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
 #ifdef LIBXML_SGML_ENABLED
 	case XML_SGML_DOCUMENT_NODE:
 #endif
 	    return(NULL);
 	case XML_NAMESPACE_DECL:
-	    /* TODO !!! */
-	    return(NULL);
+	    return(xmlStrdup(((xmlNsPtr)cur)->href));
         case XML_ELEMENT_DECL:
 	    /* TODO !!! */
 	    return(NULL);
@@ -3084,7 +3222,7 @@
 	    }
 	    if (cur->children != NULL) xmlFreeNodeList(cur->children);
 	    cur->children = xmlStringGetNodeList(cur->doc, content);
-	    UPDATE_LAST_CHILD(cur)
+	    UPDATE_LAST_CHILD_AND_PARENT(cur)
 	    break;
         case XML_ATTRIBUTE_NODE:
 	    break;
@@ -3118,6 +3256,8 @@
         case XML_DOCUMENT_NODE:
         case XML_HTML_DOCUMENT_NODE:
         case XML_DOCUMENT_TYPE_NODE:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
 #ifdef LIBXML_SGML_ENABLED
 	case XML_SGML_DOCUMENT_NODE:
 #endif
@@ -3170,7 +3310,7 @@
 	    }
 	    if (cur->children != NULL) xmlFreeNodeList(cur->children);
 	    cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
-	    UPDATE_LAST_CHILD(cur)
+	    UPDATE_LAST_CHILD_AND_PARENT(cur)
 	    break;
         case XML_ATTRIBUTE_NODE:
 	    break;
@@ -3207,6 +3347,8 @@
         case XML_HTML_DOCUMENT_NODE:
         case XML_DOCUMENT_TYPE_NODE:
 	case XML_NAMESPACE_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
 #ifdef LIBXML_SGML_ENABLED
 	case XML_SGML_DOCUMENT_NODE:
 #endif
@@ -3256,7 +3398,7 @@
 		    cur->children = xmlStringGetNodeList(cur->doc,
 			                       xmlBufferContent(cur->content));
 #endif
-		    UPDATE_LAST_CHILD(cur)
+		    UPDATE_LAST_CHILD_AND_PARENT(cur)
 #ifndef XML_USE_BUFFER_CONTENT
 		    xmlFree(cur->content);
 #else
@@ -3296,6 +3438,8 @@
         case XML_HTML_DOCUMENT_NODE:
         case XML_DOCUMENT_TYPE_NODE:
 	case XML_NAMESPACE_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
 #ifdef LIBXML_SGML_ENABLED
 	case XML_SGML_DOCUMENT_NODE:
 #endif
@@ -3944,12 +4088,14 @@
 	    if (prop->children != NULL) 
 	        xmlFreeNodeList(prop->children);
 	    prop->children = NULL;
+	    prop->last = NULL;
 	    if (value != NULL) {
 	        xmlChar *buffer;
 		xmlNodePtr tmp;
 
 		buffer = xmlEncodeEntitiesReentrant(node->doc, value);
 		prop->children = xmlStringGetNodeList(node->doc, buffer);
+		prop->last = NULL;
 		tmp = prop->children;
 		while (tmp != NULL) {
 		    tmp->parent = (xmlNodePtr) prop;
@@ -3993,12 +4139,16 @@
  */
 int
 xmlIsBlankNode(xmlNodePtr node) {
-    xmlChar *cur;
+    const xmlChar *cur;
     if (node == NULL) return(0);
 
     if (node->type != XML_TEXT_NODE) return(0);
     if (node->content == NULL) return(1);
+#ifndef XML_USE_BUFFER_CONTENT
     cur = node->content;
+#else
+    cur = xmlBufferContent(node->content);
+#endif
     while (*cur != 0) {
 	if (!IS_BLANK(*cur)) return(0);
 	cur++;
@@ -4749,6 +4899,10 @@
 #endif
 	return;
     }
+    if (cur->type == XML_XINCLUDE_START)
+	return;
+    if (cur->type == XML_XINCLUDE_END)
+	return;
     if (cur->type == XML_DTD_NODE) {
         xmlDtdDump(buf, (xmlDtdPtr) cur);
 	return;
@@ -5201,6 +5355,10 @@
 #endif
 	return;
     }
+    if (cur->type == XML_XINCLUDE_START)
+	return;
+    if (cur->type == XML_XINCLUDE_END)
+	return;
     if (cur->type == XML_DTD_NODE) {
         xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
 	return;
diff --git a/tree.h b/tree.h
index 8c4f708..2168d4f 100644
--- a/tree.h
+++ b/tree.h
@@ -41,9 +41,11 @@
     XML_ELEMENT_DECL=		15,
     XML_ATTRIBUTE_DECL=		16,
     XML_ENTITY_DECL=		17,
-    XML_NAMESPACE_DECL=		18
+    XML_NAMESPACE_DECL=		18,
+    XML_XINCLUDE_START=		19,
+    XML_XINCLUDE_END=		20
 #ifdef LIBXML_SGML_ENABLED
-   ,XML_SGML_DOCUMENT_NODE=	19
+   ,XML_SGML_DOCUMENT_NODE=	21
 #endif
 } xmlElementType;
 
diff --git a/uri.c b/uri.c
index a6d9f00..1ef6687 100644
--- a/uri.c
+++ b/uri.c
@@ -22,6 +22,13 @@
 #include <libxml/uri.h>
 #include <libxml/xmlerror.h>
 
+/************************************************************************
+ *									*
+ *		Macros to differenciate various character type		*
+ *			directly extracted from RFC 2396		*
+ *									*
+ ************************************************************************/
+
 /*
  * alpha    = lowalpha | upalpha
  */
@@ -169,6 +176,12 @@
  * path          = [ abs_path | opaque_part ]
  */
 
+/************************************************************************
+ *									*
+ *			Generic URI structure functions			*
+ *									*
+ ************************************************************************/
+
 /**
  * xmlCreateURI:
  *
@@ -587,6 +600,143 @@
     xmlFree(uri);
 }
 
+/************************************************************************
+ *									*
+ *			Helper functions				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlNormalizeURIPath:
+ * @path:  pointer to the path string
+ *
+ * applies the 5 normalization steps to a path string
+ * Normalization occurs directly on the string, no new allocation is done
+ *
+ * Returns 0 or an error code
+ */
+int
+xmlNormalizeURIPath(char *path) {
+    int cur, out;
+
+    if (path == NULL)
+	return(-1);
+    cur = 0;
+    out = 0;
+    while ((path[cur] != 0) && (path[cur] != '/')) cur++;
+    if (path[cur] == 0)
+	return(0);
+
+    /* we are positionned at the beginning of the first segment */
+    cur++;
+    out = cur;
+
+    /*
+     * Analyze each segment in sequence.
+     */
+    while (path[cur] != 0) {
+	/*
+	 * c) All occurrences of "./", where "." is a complete path segment,
+	 *    are removed from the buffer string.
+	 */
+	if ((path[cur] == '.') && (path[cur + 1] == '/')) {
+	    cur += 2;
+	    continue;
+	}
+
+	/*
+	 * d) If the buffer string ends with "." as a complete path segment,
+	 *    that "." is removed.
+	 */
+	if ((path[cur] == '.') && (path[cur + 1] == 0)) {
+	    path[out] = 0;
+	    break;
+	}
+
+	/* read the segment */
+	while ((path[cur] != 0) && (path[cur] != '/')) {
+	    path[out++] = path[cur++];
+	}
+	path[out++] = path[cur];
+	if (path[cur] != 0) {
+	    cur++;
+	}
+    }
+
+    cur = 0;
+    out = 0;
+    while ((path[cur] != 0) && (path[cur] != '/')) cur++;
+    if (path[cur] == 0)
+	return(0);
+    /* we are positionned at the beginning of the first segment */
+    cur++;
+    out = cur;
+    /*
+     * Analyze each segment in sequence.
+     */
+    while (path[cur] != 0) {
+	/*
+	 * e) All occurrences of "<segment>/../", where <segment> is a
+	 *    complete path segment not equal to "..", are removed from the
+	 *    buffer string.  Removal of these path segments is performed
+	 *    iteratively, removing the leftmost matching pattern on each
+	 *    iteration, until no matching pattern remains.
+	 */
+	if ((cur > 1) && (out > 1) &&
+	    (path[cur] == '/') && (path[cur + 1] == '.') &&
+	    (path[cur + 2] == '.') && (path[cur + 3] == '/') &&
+	    ((path[out] != '.') || (path[out - 1] != '.') ||
+	     (path[out - 2] != '/'))) {
+	    cur += 3;
+	    out --;
+	    while ((out > 0) && (path[out] != '/')) { out --; }
+	    path[out] = 0;
+            continue;
+	}
+
+	/*
+	 * f) If the buffer string ends with "<segment>/..", where <segment>
+	 *    is a complete path segment not equal to "..", that
+	 *    "<segment>/.." is removed.
+	 */
+	if ((path[cur] == '/') && (path[cur + 1] == '.') &&
+	    (path[cur + 2] == '.') && (path[cur + 3] == 0) &&
+	    ((path[out] != '.') || (path[out - 1] != '.') ||
+	     (path[out - 2] != '/'))) {
+	    cur += 4;
+	    out --;
+	    while ((out > 0) && (path[out - 1] != '/')) { out --; }
+	    path[out] = 0;
+            continue;
+	}
+        
+	path[out++] = path[cur++]; /* / or 0 */
+    }
+    path[out] = 0;
+
+    /*
+     * g) If the resulting buffer string still begins with one or more
+     *    complete path segments of "..", then the reference is 
+     *    considered to be in error. Implementations may handle this
+     *    error by retaining these components in the resolved path (i.e.,
+     *    treating them as part of the final URI), by removing them from
+     *    the resolved path (i.e., discarding relative levels above the
+     *    root), or by avoiding traversal of the reference.
+     *
+     * We discard them from the final path.
+     */
+    cur = 0;
+    while ((path[cur] == '/') && (path[cur + 1] == '.') &&
+	   (path[cur + 2] == '.'))
+	cur += 3;
+    if (cur != 0) {
+	out = 0;
+	while (path[cur] != 0) path[out++] = path[cur++];
+	path[out] = 0;
+    }
+    return(0);
+}
+
 /**
  * xmlURIUnescapeString:
  * @str:  the string to unescape
@@ -647,6 +797,74 @@
     return(ret);
 }
 
+/**
+ * xmlURIEscape:
+ * @str:  the string of the URI to escape
+ *
+ * Escaping routine, does not do validity checks !
+ * It will try to escape the chars needing this, but this is heuristic
+ * based it's impossible to be sure.
+ *
+ * Returns an copy of the string, but escaped
+ */
+xmlChar *
+xmlURIEscape(const xmlChar *str) {
+    xmlChar *ret;
+    const xmlChar *in;
+    unsigned int len, out;
+
+    if (str == NULL)
+	return(NULL);
+    len = xmlStrlen(str);
+    if (len <= 0) return(NULL);
+
+    len += 20;
+    ret = (xmlChar *) xmlMalloc(len);
+    if (ret == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlURIEscape: out of memory\n");
+	return(NULL);
+    }
+    in = (const xmlChar *) str;
+    out = 0;
+    while(*in != 0) {
+	if (len - out <= 3) {
+	    len += 20;
+	    ret = (xmlChar *) xmlRealloc(ret, len);
+	    if (ret == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"xmlURIEscape: out of memory\n");
+		return(NULL);
+	    }
+	}
+	if ((!IS_UNRESERVED(*in)) && (*in != ':') && (*in != '/') &&
+	    (*in != '?') && (*in != '#')) {
+	    unsigned char val;
+	    ret[out++] = '%';
+	    val = *in >> 4;
+	    if (val <= 9)
+		ret[out++] = '0' + val;
+	    else
+		ret[out++] = 'A' + val - 0xA;
+	    val = *in & 0xF;
+	    if (val <= 9)
+		ret[out++] = '0' + val;
+	    else
+		ret[out++] = 'A' + val - 0xA;
+	    in++;
+	} else {
+	    ret[out++] = *in++;
+	}
+    }
+    ret[out] = 0;
+    return(ret);
+}
+
+/************************************************************************
+ *									*
+ *			Escaped URI parsing				*
+ *									*
+ ************************************************************************/
 
 /**
  * xmlParseURIFragment:
@@ -1284,136 +1502,11 @@
     return(uri);
 }
 
-/**
- * xmlNormalizeURIPath:
- * @path:  pointer to the path string
- *
- * applies the 5 normalization steps to a path string
- * Normalization occurs directly on the string, no new allocation is done
- *
- * Returns 0 or an error code
- */
-int
-xmlNormalizeURIPath(char *path) {
-    int cur, out;
-
-    if (path == NULL)
-	return(-1);
-    cur = 0;
-    out = 0;
-    while ((path[cur] != 0) && (path[cur] != '/')) cur++;
-    if (path[cur] == 0)
-	return(0);
-
-    /* we are positionned at the beginning of the first segment */
-    cur++;
-    out = cur;
-
-    /*
-     * Analyze each segment in sequence.
-     */
-    while (path[cur] != 0) {
-	/*
-	 * c) All occurrences of "./", where "." is a complete path segment,
-	 *    are removed from the buffer string.
-	 */
-	if ((path[cur] == '.') && (path[cur + 1] == '/')) {
-	    cur += 2;
-	    continue;
-	}
-
-	/*
-	 * d) If the buffer string ends with "." as a complete path segment,
-	 *    that "." is removed.
-	 */
-	if ((path[cur] == '.') && (path[cur + 1] == 0)) {
-	    path[out] = 0;
-	    break;
-	}
-
-	/* read the segment */
-	while ((path[cur] != 0) && (path[cur] != '/')) {
-	    path[out++] = path[cur++];
-	}
-	path[out++] = path[cur];
-	if (path[cur] != 0) {
-	    cur++;
-	}
-    }
-
-    cur = 0;
-    out = 0;
-    while ((path[cur] != 0) && (path[cur] != '/')) cur++;
-    if (path[cur] == 0)
-	return(0);
-    /* we are positionned at the beginning of the first segment */
-    cur++;
-    out = cur;
-    /*
-     * Analyze each segment in sequence.
-     */
-    while (path[cur] != 0) {
-	/*
-	 * e) All occurrences of "<segment>/../", where <segment> is a
-	 *    complete path segment not equal to "..", are removed from the
-	 *    buffer string.  Removal of these path segments is performed
-	 *    iteratively, removing the leftmost matching pattern on each
-	 *    iteration, until no matching pattern remains.
-	 */
-	if ((cur > 1) && (out > 1) &&
-	    (path[cur] == '/') && (path[cur + 1] == '.') &&
-	    (path[cur + 2] == '.') && (path[cur + 3] == '/') &&
-	    ((path[out] != '.') || (path[out - 1] != '.') ||
-	     (path[out - 2] != '/'))) {
-	    cur += 3;
-	    out --;
-	    while ((out > 0) && (path[out] != '/')) { out --; }
-	    path[out] = 0;
-            continue;
-	}
-
-	/*
-	 * f) If the buffer string ends with "<segment>/..", where <segment>
-	 *    is a complete path segment not equal to "..", that
-	 *    "<segment>/.." is removed.
-	 */
-	if ((path[cur] == '/') && (path[cur + 1] == '.') &&
-	    (path[cur + 2] == '.') && (path[cur + 3] == 0) &&
-	    ((path[out] != '.') || (path[out - 1] != '.') ||
-	     (path[out - 2] != '/'))) {
-	    cur += 4;
-	    out --;
-	    while ((out > 0) && (path[out - 1] != '/')) { out --; }
-	    path[out] = 0;
-            continue;
-	}
-        
-	path[out++] = path[cur++]; /* / or 0 */
-    }
-    path[out] = 0;
-
-    /*
-     * g) If the resulting buffer string still begins with one or more
-     *    complete path segments of "..", then the reference is 
-     *    considered to be in error. Implementations may handle this
-     *    error by retaining these components in the resolved path (i.e.,
-     *    treating them as part of the final URI), by removing them from
-     *    the resolved path (i.e., discarding relative levels above the
-     *    root), or by avoiding traversal of the reference.
-     *
-     * We discard them from the final path.
-     */
-    cur = 0;
-    while ((path[cur] == '/') && (path[cur + 1] == '.') &&
-	   (path[cur + 2] == '.'))
-	cur += 3;
-    if (cur != 0) {
-	out = 0;
-	while (path[cur] != 0) path[out++] = path[cur++];
-	path[out] = 0;
-    }
-    return(0);
-}
+/************************************************************************
+ *									*
+ *			Public functions				*
+ *									*
+ ************************************************************************/
 
 /**
  * xmlBuildURI:
diff --git a/uri.h b/uri.h
index 705e385..e7aeda4 100644
--- a/uri.h
+++ b/uri.h
@@ -52,6 +52,7 @@
 					 int len,
 					 char *target);
 int		xmlNormalizeURIPath	(char *path);
+xmlChar *	xmlURIEscape		(const xmlChar *str);
 void		xmlFreeURI		(xmlURIPtr uri);
 
 #ifdef __cplusplus
diff --git a/valid.c b/valid.c
index 8cbfd53..7e6e12a 100644
--- a/valid.c
+++ b/valid.c
@@ -3212,6 +3212,7 @@
             case XML_DOCUMENT_TYPE_NODE:
             case XML_DOCUMENT_FRAG_NODE:
             case XML_NOTATION_NODE:
+	    case XML_NAMESPACE_DECL:
 	         strcat(buf, "???");
 		 if (cur->next != NULL)
 		     strcat(buf, " ");
@@ -3223,6 +3224,8 @@
 	    case XML_ELEMENT_DECL:
 	    case XML_ATTRIBUTE_DECL:
 	    case XML_ENTITY_DECL:
+	    case XML_XINCLUDE_START:
+	    case XML_XINCLUDE_END:
 		 break;
 	}
 	cur = cur->next;
diff --git a/xinclude.c b/xinclude.c
new file mode 100644
index 0000000..3a3bf67
--- /dev/null
+++ b/xinclude.c
@@ -0,0 +1,737 @@
+/*
+ * xinclude.c : Code to implement XInclude processing
+ *
+ * World Wide Web Consortium Working Draft 26 October 2000
+ * http://www.w3.org/TR/2000/WD-xinclude-20001026
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+/*
+ * TODO: compute XPointers nodesets
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/uri.h>
+#include <libxml/xpointer.h>
+#include <libxml/parserInternals.h>
+#ifdef LIBXML_DEBUG_ENABLED
+#include <libxml/debugXML.h>
+#endif
+#include <libxml/xmlerror.h>
+
+#ifdef LIBXML_XINCLUDE_ENABLED
+#include <libxml/xinclude.h>
+
+#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/1999/XML/xinclude"
+#define XINCLUDE_NODE (const xmlChar *) "include"
+#define XINCLUDE_HREF (const xmlChar *) "href"
+#define XINCLUDE_PARSE (const xmlChar *) "parse"
+#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
+#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
+
+/* #define DEBUG_XINCLUDE  */
+
+/************************************************************************
+ *									*
+ *			XInclude contexts handling			*
+ *									*
+ ************************************************************************/
+
+/*
+ * An XInclude context
+ */
+typedef xmlChar *URL;
+typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
+typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
+struct _xmlXIncludeCtxt {
+    xmlDocPtr             doc; /* the source document */
+    int                 incNr; /* number of includes */
+    int                incMax; /* size of includes tab */
+    xmlNodePtr        *incTab; /* array of include nodes */
+    xmlNodePtr        *repTab; /* array of replacement node lists */
+    int                 docNr; /* number of parsed documents */
+    int                docMax; /* size of parsed documents tab */
+    xmlDocPtr         *docTab; /* array of parsed documents */
+    URL               *urlTab; /* array of parsed documents URLs */
+    int                 txtNr; /* number of unparsed documents */
+    int                txtMax; /* size of unparsed documents tab */
+    xmlNodePtr        *txtTab; /* array of unparsed text nodes */
+    URL            *txturlTab; /* array of unparsed txtuments URLs */
+};
+
+/**
+ * xmlXIncludeAddNode:
+ * @ctxt:  the XInclude context
+ * @node:  the new node
+ * 
+ * Add a new node to process to an XInclude context
+ */
+void
+xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
+    if (ctxt->incMax == 0) {
+	ctxt->incMax = 4;
+        ctxt->incTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
+		                          sizeof(ctxt->incTab[0]));
+        if (ctxt->incTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+        ctxt->repTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
+		                          sizeof(ctxt->repTab[0]));
+        if (ctxt->repTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+    }
+    if (ctxt->incNr >= ctxt->incMax) {
+	ctxt->incMax *= 2;
+        ctxt->incTab = (xmlNodePtr *) xmlRealloc(ctxt->incTab,
+	             ctxt->incMax * sizeof(ctxt->incTab[0]));
+        if (ctxt->incTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+        ctxt->repTab = (xmlNodePtr *) xmlRealloc(ctxt->repTab,
+	             ctxt->incMax * sizeof(ctxt->repTab[0]));
+        if (ctxt->repTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+    }
+    ctxt->incTab[ctxt->incNr] = node;
+    ctxt->repTab[ctxt->incNr] = NULL;
+    ctxt->incNr++;
+}
+
+/**
+ * xmlXIncludeAddDoc:
+ * @ctxt:  the XInclude context
+ * @doc:  the new document
+ * @url:  the associated URL
+ * 
+ * Add a new document to the list
+ */
+void
+xmlXIncludeAddDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const URL url) {
+    if (ctxt->docMax == 0) {
+	ctxt->docMax = 4;
+        ctxt->docTab = (xmlDocPtr *) xmlMalloc(ctxt->docMax *
+		                          sizeof(ctxt->docTab[0]));
+        if (ctxt->docTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+        ctxt->urlTab = (URL *) xmlMalloc(ctxt->docMax *
+		                          sizeof(ctxt->urlTab[0]));
+        if (ctxt->urlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+    }
+    if (ctxt->docNr >= ctxt->docMax) {
+	ctxt->docMax *= 2;
+        ctxt->docTab = (xmlDocPtr *) xmlRealloc(ctxt->docTab,
+	             ctxt->docMax * sizeof(ctxt->docTab[0]));
+        if (ctxt->docTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+        ctxt->urlTab = (URL *) xmlRealloc(ctxt->urlTab,
+	             ctxt->docMax * sizeof(ctxt->urlTab[0]));
+        if (ctxt->urlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+    }
+    ctxt->docTab[ctxt->docNr] = doc;
+    ctxt->urlTab[ctxt->docNr] = xmlStrdup(url);
+    ctxt->docNr++;
+}
+
+/**
+ * xmlXIncludeAddTxt:
+ * @ctxt:  the XInclude context
+ * @txt:  the new text node
+ * @url:  the associated URL
+ * 
+ * Add a new txtument to the list
+ */
+void
+xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const URL url) {
+    if (ctxt->txtMax == 0) {
+	ctxt->txtMax = 4;
+        ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
+		                          sizeof(ctxt->txtTab[0]));
+        if (ctxt->txtTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+        ctxt->txturlTab = (URL *) xmlMalloc(ctxt->txtMax *
+		                          sizeof(ctxt->txturlTab[0]));
+        if (ctxt->txturlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+    }
+    if (ctxt->txtNr >= ctxt->txtMax) {
+	ctxt->txtMax *= 2;
+        ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
+	             ctxt->txtMax * sizeof(ctxt->txtTab[0]));
+        if (ctxt->txtTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+        ctxt->txturlTab = (URL *) xmlRealloc(ctxt->txturlTab,
+	             ctxt->txtMax * sizeof(ctxt->urlTab[0]));
+        if (ctxt->txturlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+    }
+    ctxt->txtTab[ctxt->txtNr] = txt;
+    ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
+    ctxt->txtNr++;
+}
+
+/**
+ * xmlXIncludeNewContext:
+ * @doc:  an XML Document
+ *
+ * Creates a new XInclude context
+ *
+ * Returns the new set
+ */
+xmlXIncludeCtxtPtr
+xmlXIncludeNewContext(xmlDocPtr doc) {
+    xmlXIncludeCtxtPtr ret;
+
+    if (doc == NULL)
+	return(NULL);
+    ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
+    if (ret == NULL)
+	return(NULL);
+    memset(ret, 0, sizeof(xmlXIncludeCtxt));
+    ret->doc = doc;
+    ret->incNr = 0;
+    ret->incMax = 0;
+    ret->incTab = NULL;
+    ret->repTab = NULL;
+    ret->docNr = 0;
+    ret->docMax = 0;
+    ret->docTab = NULL;
+    ret->urlTab = NULL;
+    return(ret);
+}
+
+/**
+ * xmlXIncludeFreeContext:
+ * @ctxt: the XInclude context
+ *
+ * Free an XInclude context
+ */
+void
+xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
+    if (ctxt == NULL)
+	return;
+    if (ctxt->incTab != NULL)
+	xmlFree(ctxt->incTab);
+    if (ctxt->repTab != NULL)
+	xmlFree(ctxt->repTab);
+    memset(ctxt, 0xeb, sizeof(xmlXIncludeCtxt));
+    xmlFree(ctxt);
+}
+
+/************************************************************************
+ *									*
+ *			XInclude I/O handling				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXIncludeLoadDoc:
+ * @ctxt:  the XInclude context
+ * @url:  the associated URL
+ * @nr:  the xinclude node number
+ * 
+ * Load the document, and store the result in the XInclude context
+ */
+void
+xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
+    xmlDocPtr doc;
+    xmlURIPtr uri;
+    xmlChar *URL;
+    int i;
+    /*
+     * Check the URL and remove any fragment identifier
+     */
+    uri = xmlParseURI((const char *)url);
+    if (uri == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: invalid value URI %s\n", url);
+	return;
+    }
+    if (uri->fragment != NULL) {
+	xmlFree(uri->fragment);
+	uri->fragment = NULL; /* TODO: kkep it for later processing */
+    }
+    URL = xmlSaveUri(uri);
+    xmlFreeURI(uri);
+    if (URL == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: invalid value URI %s\n", url);
+	return;
+    }
+
+    /*
+     * Handling of references to the local document are done
+     * directly through ctxt->doc.
+     */
+    if (URL[0] == 0) {
+	xmlFree(URL);
+	return;
+    }
+
+    /*
+     * Prevent reloading twice the document.
+     */
+    for (i = 0; i < ctxt->docNr; i++) {
+	if (xmlStrEqual(URL, ctxt->urlTab[i])) {
+	    doc = ctxt->docTab[i];
+	    goto loaded;
+	}
+    }
+    /*
+     * Load it.
+     */
+    doc = xmlParseFile((const char *)URL);
+    if (doc == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: could not load %s\n", URL);
+	xmlFree(URL);
+	return;
+    }
+    xmlXIncludeAddDoc(ctxt, doc, URL);
+
+loaded:
+    /*
+     * Add the top children list as the replacement copy.
+     */
+    ctxt->repTab[nr] = xmlCopyNodeList(doc->children);
+    xmlFree(URL);
+}
+
+/**
+ * xmlXIncludeLoadTxt:
+ * @ctxt:  the XInclude context
+ * @url:  the associated URL
+ * @nr:  the xinclude node number
+ * 
+ * Load the content, and store the result in the XInclude context
+ */
+void
+xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
+    xmlParserInputBufferPtr buf;
+    xmlNodePtr node;
+    xmlURIPtr uri;
+    xmlChar *URL;
+    int i;
+    /*
+     * Check the URL and remove any fragment identifier
+     */
+    uri = xmlParseURI((const char *)url);
+    if (uri == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: invalid value URI %s\n", url);
+	return;
+    }
+    if (uri->fragment != NULL) {
+	xmlFreeURI(uri);
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: fragment identifier forbidden for text\n");
+	return;
+    }
+    URL = xmlSaveUri(uri);
+    xmlFreeURI(uri);
+    if (URL == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: invalid value URI %s\n", url);
+	return;
+    }
+
+    /*
+     * Handling of references to the local document are done
+     * directly through ctxt->doc.
+     */
+    if (URL[0] == 0) {
+	xmlGenericError(xmlGenericErrorContext,
+		"XInclude: text serialization of document not available\n");
+	xmlFree(URL);
+	return;
+    }
+
+    /*
+     * Prevent reloading twice the document.
+     */
+    for (i = 0; i < ctxt->txtNr; i++) {
+	if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
+	    node = xmlCopyNode(ctxt->txtTab[i], 1);
+	    goto loaded;
+	}
+    }
+    /*
+     * Load it.
+     * Issue 62: how to detect the encoding
+     */
+    buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
+    if (buf == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: could not load %s\n", URL);
+	xmlFree(URL);
+	return;
+    }
+    node = xmlNewText(NULL);
+
+    /*
+     * Scan all chars from the resource and add the to the node
+     */
+    while (xmlParserInputBufferRead(buf, 128) > 0) {
+	int len;
+	const xmlChar *content;
+
+	content = xmlBufferContent(buf->buffer);
+	len = xmlBufferLength(buf->buffer);
+	for (i = 0;i < len; i++) {
+	    /*
+	     * TODO: if the encoding issue is solved, scan UTF8 chars instead
+	     */
+	    if (!IS_CHAR(content[i])) {
+		xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: %s contains invalid char %d\n", URL, content[i]);
+	    } else {
+		xmlNodeAddContentLen(node, &content[i], 1);
+	    }
+	}
+	xmlBufferShrink(buf->buffer, len);
+    }
+    xmlFreeParserInputBuffer(buf);
+    xmlXIncludeAddTxt(ctxt, node, URL);
+
+loaded:
+    /*
+     * Add the element as the replacement copy.
+     */
+    ctxt->repTab[nr] = node;
+    xmlFree(URL);
+}
+
+/************************************************************************
+ *									*
+ *			XInclude Processing				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXIncludePreProcessNode:
+ * @ctxt: an XInclude context
+ * @node: an XInclude node
+ *
+ * Implement the infoset replacement lookup on the XML element @node
+ *
+ * Returns the result list or NULL in case of error
+ */
+xmlNodePtr
+xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
+    xmlXIncludeAddNode(ctxt, node);
+    return(0);
+}
+
+/**
+ * xmlXIncludeLoadNode:
+ * @ctxt: an XInclude context
+ * @nr: the node number
+ *
+ * Find and load the infoset replacement for the given node.
+ *
+ * Returns 0 if substition succeeded, -1 if some processing failed
+ */
+int
+xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
+    xmlNodePtr cur;
+    xmlChar *href;
+    xmlChar *parse;
+    xmlChar *base;
+    xmlChar *URI;
+    int xml = 1; /* default Issue 64 */
+
+    if (ctxt == NULL)
+	return(-1);
+    if ((nr < 0) || (nr >= ctxt->incNr))
+	return(-1);
+    cur = ctxt->incTab[nr];
+    if (cur == NULL)
+	return(-1);
+
+#ifdef DEBUG_XINCLUDE
+    xmlDebugDumpNode(stdout, cur, 0);
+#endif
+    /*
+     * read the attributes
+     */
+    href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
+    if (href == NULL) {
+	href = xmlGetProp(cur, XINCLUDE_HREF);
+	if (href == NULL) {
+	    xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
+	    return(-1);
+	}
+    }
+    parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
+    if (parse == NULL) {
+	parse = xmlGetProp(cur, XINCLUDE_PARSE);
+    }
+    if (parse != NULL) {
+	if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
+	    xml = 1;
+	else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
+	    xml = 0;
+	else {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: invalid value %s for %s\n",
+		            parse, XINCLUDE_PARSE);
+	    if (href != NULL)
+		xmlFree(href);
+	    if (parse != NULL)
+		xmlFree(parse);
+	    return(-1);
+	}
+    }
+
+    /*
+     * compute the URI
+     */
+    base = xmlNodeGetBase(ctxt->doc, cur);
+    URI = xmlBuildURI(href, base);
+    if (URI == NULL) {
+	xmlChar *escbase;
+	xmlChar *eschref;
+	/*
+	 * Some escapeing may be needed
+	 */
+	escbase = xmlURIEscape(base);
+	eschref = xmlURIEscape(href);
+	URI = xmlBuildURI(eschref, escbase);
+	if (escbase != NULL)
+	    xmlFree(escbase);
+	if (eschref != NULL)
+	    xmlFree(eschref);
+    }
+    if (URI == NULL) {
+	xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
+	if (parse != NULL)
+	    xmlFree(parse);
+	if (href != NULL)
+	    xmlFree(href);
+	if (base != NULL)
+	    xmlFree(base);
+	return(-1);
+    }
+#ifdef DEBUG_XINCLUDE
+    xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
+	    xml ? "xml": "text");
+    xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
+#endif
+
+    /*
+     * Cleanup
+     */
+    if (xml) {
+	xmlXIncludeLoadDoc(ctxt, URI, nr);
+	/* xmlXIncludeGetFragment(ctxt, cur, URI); */
+    } else {
+	xmlXIncludeLoadTxt(ctxt, URI, nr);
+    }
+
+    /*
+     * Cleanup
+     */
+    if (URI != NULL)
+	xmlFree(URI);
+    if (parse != NULL)
+	xmlFree(parse);
+    if (href != NULL)
+	xmlFree(href);
+    if (base != NULL)
+	xmlFree(base);
+    return(0);
+}
+
+/**
+ * xmlXIncludeIncludeNode:
+ * @ctxt: an XInclude context
+ * @nr: the node number
+ *
+ * Inplement the infoset replacement for the given node
+ *
+ * Returns 0 if substition succeeded, -1 if some processing failed
+ */
+int
+xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
+    xmlNodePtr cur, end, list;
+
+    if (ctxt == NULL)
+	return(-1);
+    if ((nr < 0) || (nr >= ctxt->incNr))
+	return(-1);
+    cur = ctxt->incTab[nr];
+    if (cur == NULL)
+	return(-1);
+
+    /*
+     * Change the current node as an XInclude start one, and add an
+     * entity end one
+     */
+    cur->type = XML_XINCLUDE_START;
+    end = xmlNewNode(cur->ns, cur->name);
+    if (end == NULL) {
+	xmlGenericError(xmlGenericErrorContext, 
+		"XInclude: failed to build node\n");
+	return(-1);
+    }
+    end->type = XML_XINCLUDE_END;
+    xmlAddNextSibling(cur, end);
+
+    /*
+     * Add the list of nodes
+     */
+    list = ctxt->repTab[nr];
+    ctxt->repTab[nr] = NULL;
+    while (list != NULL) {
+	cur = list;
+	list = list->next;
+
+        xmlAddPrevSibling(end, cur);
+    }
+    return(0);
+}
+
+/**
+ * xmlXIncludeTestNode:
+ * @doc: an XML document
+ * @node: an XInclude node
+ *
+ * test if the node is an XInclude node
+ *
+ * Returns 1 true, 0 otherwise
+ */
+int
+xmlXIncludeTestNode(xmlDocPtr doc, xmlNodePtr node) {
+    if (node == NULL)
+	return(0);
+    if (node->ns == NULL)
+	return(0);
+    if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
+	(xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
+    return(0);
+}
+
+/**
+ * xmlXIncludeProcess:
+ * @doc: an XML document
+ *
+ * Implement the XInclude substitution on the XML document @doc
+ *
+ * Returns 0 if no substition were done, -1 if some processing failed
+ *    or the number of substitutions done.
+ */
+int
+xmlXIncludeProcess(xmlDocPtr doc) {
+    xmlXIncludeCtxtPtr ctxt;
+    xmlNodePtr cur;
+    int ret = 0;
+    int i;
+
+    if (doc == NULL)
+	return(-1);
+    ctxt = xmlXIncludeNewContext(doc);
+    if (ctxt == NULL)
+	return(-1);
+
+    /*
+     * First phase: lookup the elements in the document
+     */
+    cur = xmlDocGetRootElement(doc);
+    if (xmlXIncludeTestNode(doc, cur))
+	xmlXIncludePreProcessNode(ctxt, cur);
+    while (cur != NULL) {
+	/* TODO: need to work on entities -> stack */
+	if ((cur->children != NULL) &&
+	    (cur->children->type != XML_ENTITY_DECL)) {
+	    cur = cur->children;
+	    if (xmlXIncludeTestNode(doc, cur))
+		xmlXIncludePreProcessNode(ctxt, cur);
+	} else if (cur->next != NULL) {
+	    cur = cur->next;
+	    if (xmlXIncludeTestNode(doc, cur))
+		xmlXIncludePreProcessNode(ctxt, cur);
+	} else {
+	    do {
+		cur = cur->parent;
+		if (cur == NULL) break; /* do */
+		if (cur->next != NULL) {
+		    cur = cur->next;
+		    if (xmlXIncludeTestNode(doc, cur))
+			xmlXIncludePreProcessNode(ctxt, cur);
+		    break; /* do */
+		}
+	    } while (cur != NULL);
+	}
+    }
+
+    /*
+     * Second Phase : collect the infosets fragments
+     */
+    for (i = 0;i < ctxt->incNr; i++) {
+        xmlXIncludeLoadNode(ctxt, i);
+    }
+
+    /*
+     * Third phase: extend the original document infoset.
+     */
+    for (i = 0;i < ctxt->incNr; i++) {
+	xmlXIncludeIncludeNode(ctxt, i);
+    }
+
+    /*
+     * Cleanup
+     */
+    xmlXIncludeFreeContext(ctxt);
+    return(ret);
+}
+
+#else /* !LIBXML_XINCLUDE_ENABLED */
+#endif
diff --git a/xinclude.h b/xinclude.h
new file mode 100644
index 0000000..eca4588
--- /dev/null
+++ b/xinclude.h
@@ -0,0 +1,26 @@
+/*
+ * xinclude.c : API to handle XInclude processing
+ *
+ * World Wide Web Consortium Working Draft 26 October 2000
+ * http://www.w3.org/TR/2000/WD-xinclude-20001026
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_XINCLUDE_H__
+#define __XML_XINCLUDE_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int	xmlXIncludeProcess	(xmlDocPtr doc);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_XINCLUDE_H__ */
diff --git a/xmllint.c b/xmllint.c
index 5ce88e1..e443a86 100644
--- a/xmllint.c
+++ b/xmllint.c
@@ -55,6 +55,9 @@
 #include <libxml/xpath.h>
 #include <libxml/debugXML.h>
 #include <libxml/xmlerror.h>
+#ifdef LIBXML_XINCLUDE_ENABLED
+#include <libxml/xinclude.h>
+#endif
 
 #ifdef LIBXML_DEBUG_ENABLED
 static int debug = 0;
@@ -81,6 +84,9 @@
 static int noblanks = 0;
 static int testIO = 0;
 static char *encoding = NULL;
+#ifdef LIBXML_XINCLUDE_ENABLED
+static int xinclude = 0;
+#endif
 
 extern int xmlDoValidityCheckingDefaultValue;
 extern int xmlGetWarningsDefaultValue;
@@ -497,10 +503,14 @@
     /*
      * If we don't have a document we might as well give up.  Do we
      * want an error message here?  <sven@zen.org> */
-    if (doc == NULL)
-      {
+    if (doc == NULL) {
 	return;
-      }
+    }
+
+#ifdef LIBXML_XINCLUDE_ENABLED
+    if (xinclude)
+	xmlXIncludeProcess(doc);
+#endif
 
 #ifdef LIBXML_DEBUG_ENABLED
     /*
@@ -667,6 +677,11 @@
 	else if ((!strcmp(argv[i], "-testIO")) ||
 	         (!strcmp(argv[i], "--testIO")))
 	    testIO++;
+#ifdef LIBXML_XINCLUDE_ENABLED
+	else if ((!strcmp(argv[i], "-xinclude")) ||
+	         (!strcmp(argv[i], "--xinclude")))
+	    xinclude++;
+#endif
 	else if ((!strcmp(argv[i], "-compress")) ||
 	         (!strcmp(argv[i], "--compress"))) {
 	    compress++;
@@ -773,6 +788,9 @@
 	printf("\t--noblanks : drop (ignorable?) blanks spaces\n");
 	printf("\t--testIO : test user I/O support\n");
 	printf("\t--encode encoding : output in the given encoding\n");
+#ifdef LIBXML_XINCLUDE_ENABLED
+	printf("\t--xinclude : do XInclude processing\n");
+#endif
     }
     xmlCleanupParser();
     xmlMemoryDump();
diff --git a/xmlversion.h.in b/xmlversion.h.in
index 01b1ea1..4d21762 100644
--- a/xmlversion.h.in
+++ b/xmlversion.h.in
@@ -78,6 +78,15 @@
 #endif
 
 /*
+ * Whether XInclude is configured in
+ */
+#if @WITH_XINCLUDE@
+#define LIBXML_XINCLUDE_ENABLED
+#else
+#define LIBXML_XINCLUDE_DISABLED
+#endif
+
+/*
  * Whether iconv support is available
  */
 #if @WITH_ICONV@
diff --git a/xpath.c b/xpath.c
index dbffba6..6b95b5a 100644
--- a/xpath.c
+++ b/xpath.c
@@ -597,20 +597,51 @@
  */
 xmlNodeSetPtr
 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
-    int i;
+    int i, j, initNr;
 
     if (val2 == NULL) return(val1);
     if (val1 == NULL) {
 	val1 = xmlXPathNodeSetCreate(NULL);
     }
 
-    /*
-     * !!!!! this can be optimized a lot, knowing that both
-     *       val1 and val2 already have unicity of their values.
-     */
+    initNr = val1->nodeNr;
 
-    for (i = 0;i < val2->nodeNr;i++)
-        xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
+    for (i = 0;i < val2->nodeNr;i++) {
+	/*
+	 * check against doublons
+	 */
+	for (j = 0; j < initNr; j++)
+	    if (val1->nodeTab[j] == val2->nodeTab[i]) continue;
+
+	/*
+	 * grow the nodeTab if needed
+	 */
+	if (val1->nodeMax == 0) {
+	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
+						    sizeof(xmlNodePtr));
+	    if (val1->nodeTab == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+				"xmlXPathNodeSetMerge: out of memory\n");
+		return(NULL);
+	    }
+	    memset(val1->nodeTab, 0 ,
+		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
+	    val1->nodeMax = XML_NODESET_DEFAULT;
+	} else if (val1->nodeNr == val1->nodeMax) {
+	    xmlNodePtr *temp;
+
+	    val1->nodeMax *= 2;
+	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
+					     sizeof(xmlNodePtr));
+	    if (temp == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+				"xmlXPathNodeSetMerge: out of memory\n");
+		return(NULL);
+	    }
+	    val1->nodeTab = temp;
+	}
+	val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
+    }
 
     return(val1);
 }
@@ -1922,12 +1953,12 @@
                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
 
 /**
- * mlXPathNextSelf:
+ * xmlXPathNextSelf:
  * @ctxt:  the XPath Parser context
  * @cur:  the current node in the traversal
  *
  * Traversal function for the "self" direction
- * he self axis contains just the context node itself
+ * The self axis contains just the context node itself
  *
  * Returns the next element following that axis
  */
@@ -1939,7 +1970,7 @@
 }
 
 /**
- * mlXPathNextChild:
+ * xmlXPathNextChild:
  * @ctxt:  the XPath Parser context
  * @cur:  the current node in the traversal
  *
@@ -1976,6 +2007,8 @@
 	    case XML_ENTITY_DECL:
             case XML_ATTRIBUTE_NODE:
 	    case XML_NAMESPACE_DECL:
+	    case XML_XINCLUDE_START:
+	    case XML_XINCLUDE_END:
 		return(NULL);
 	}
 	return(NULL);
@@ -1987,7 +2020,7 @@
 }
 
 /**
- * mlXPathNextDescendant:
+ * xmlXPathNextDescendant:
  * @ctxt:  the XPath Parser context
  * @cur:  the current node in the traversal
  *
@@ -2002,7 +2035,8 @@
     if (cur == NULL) {
 	if (ctxt->context->node == NULL)
 	    return(NULL);
-	if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
+	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
+	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
 	    return(NULL);
 
         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
@@ -2030,7 +2064,7 @@
 }
 
 /**
- * mlXPathNextDescendantOrSelf:
+ * xmlXPathNextDescendantOrSelf:
  * @ctxt:  the XPath Parser context
  * @cur:  the current node in the traversal
  *
@@ -2047,7 +2081,8 @@
     if (cur == NULL) {
 	if (ctxt->context->node == NULL)
 	    return(NULL);
-	if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
+	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
+	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
 	    return(NULL);
         return(ctxt->context->node);
     }
@@ -2086,6 +2121,8 @@
             case XML_DTD_NODE:
 	    case XML_ELEMENT_DECL:
 	    case XML_ATTRIBUTE_DECL:
+	    case XML_XINCLUDE_START:
+	    case XML_XINCLUDE_END:
 	    case XML_ENTITY_DECL:
 		if (ctxt->context->node->parent == NULL)
 		    return((xmlNodePtr) ctxt->context->doc);
@@ -2151,6 +2188,8 @@
 	    case XML_ATTRIBUTE_DECL:
 	    case XML_ENTITY_DECL:
             case XML_NOTATION_NODE:
+	    case XML_XINCLUDE_START:
+	    case XML_XINCLUDE_END:
 		if (ctxt->context->node->parent == NULL)
 		    return((xmlNodePtr) ctxt->context->doc);
 		return(ctxt->context->node->parent);
@@ -2194,6 +2233,8 @@
         case XML_ELEMENT_DECL:
         case XML_ATTRIBUTE_DECL:
         case XML_ENTITY_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
 	    return(cur->parent);
 	case XML_ATTRIBUTE_NODE: {
 	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
@@ -2252,6 +2293,9 @@
  */
 xmlNodePtr
 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
+	(ctxt->context->node->type == XML_NAMESPACE_DECL))
+	return(NULL);
     if (cur == (xmlNodePtr) ctxt->context->doc)
         return(NULL);
     if (cur == NULL)
@@ -2273,6 +2317,9 @@
  */
 xmlNodePtr
 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
+	(ctxt->context->node->type == XML_NAMESPACE_DECL))
+	return(NULL);
     if (cur == (xmlNodePtr) ctxt->context->doc)
         return(NULL);
     if (cur == NULL)
@@ -2303,7 +2350,7 @@
     do {
         cur = cur->parent;
         if (cur == NULL) return(NULL);
-        if (cur == ctxt->context->doc->children) return(NULL); /* !!!!!?!? */
+        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
         if (cur->next != NULL) return(cur->next);
     } while (cur != NULL);
     return(cur);
@@ -2320,13 +2367,18 @@
  */
 static int
 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
-    xmlNodePtr tmp ;
-    if (ancestor == NULL || node == NULL) return 0 ;
-    for (tmp = node ; tmp->parent != NULL ; tmp = tmp->parent) {
-        if (tmp->parent == ancestor)
-            return 1 ;
+    if ((ancestor == NULL) || (node == NULL)) return(0);
+    /* nodes need to be in the same document */
+    if (ancestor->doc != node->doc) return(0);
+    /* avoid searching if ancestor or node is the root node */
+    if (ancestor == (xmlNodePtr) node->doc) return(1);
+    if (node == (xmlNodePtr) ancestor->doc) return(0);
+    while (node->parent != NULL) {
+        if (node->parent == ancestor)
+            return(1);
+	node = node->parent;
     }
-    return 0 ;
+    return(0);
 }
 
 /**
@@ -2372,8 +2424,9 @@
  *
  * Returns the next element following that axis
  */
-xmlNsPtr
-xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
+xmlNodePtr
+xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
     if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
         if (ctxt->context->namespaces != NULL)
 	    xmlFree(ctxt->context->namespaces);
@@ -2382,7 +2435,7 @@
 	if (ctxt->context->namespaces == NULL) return(NULL);
 	ctxt->context->nsNr = 0;
     }
-    return(ctxt->context->namespaces[ctxt->context->nsNr++]);
+    return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
 }
 
 /**
@@ -2395,14 +2448,15 @@
  *
  * Returns the next element following that axis
  */
-xmlAttrPtr
-xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
+xmlNodePtr
+xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
     if (cur == NULL) {
         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
 	    return(NULL);
-        return(ctxt->context->node->properties);
+        return((xmlNodePtr)ctxt->context->node->properties);
     }
-    return(cur->next);
+    return((xmlNodePtr)cur->next);
 }
 
 /************************************************************************
@@ -2483,7 +2537,7 @@
 	    xmlGenericError(xmlGenericErrorContext,
 		    "axis 'attributes' ");
 #endif
-	    next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
+	    next = xmlXPathNextAttribute; break;
 	    break;
         case AXIS_CHILD:
 #ifdef DEBUG_STEP
@@ -2637,17 +2691,33 @@
 		    }
 		    break;
                 case NODE_TEST_ALL:
-		    if ((cur->type == XML_ELEMENT_NODE) ||
-			(cur->type == XML_DOCUMENT_NODE) ||
-			(cur->type == XML_HTML_DOCUMENT_NODE)) {
+		    if (axis == AXIS_ATTRIBUTE) {
+			if (cur->type == XML_ATTRIBUTE_NODE) {
 #ifdef DEBUG_STEP
-                        n++;
+			    n++;
 #endif
-		        xmlXPathNodeSetAdd(ret, cur);
+			    xmlXPathNodeSetAdd(ret, cur);
+			}
+		    } else if (axis == AXIS_NAMESPACE) {
+			if (cur->type == XML_NAMESPACE_DECL) {
+#ifdef DEBUG_STEP
+			    n++;
+#endif
+			    xmlXPathNodeSetAdd(ret, cur);
+			}
+		    } else {
+			if ((cur->type == XML_ELEMENT_NODE) ||
+			    (cur->type == XML_DOCUMENT_NODE) ||
+			    (cur->type == XML_HTML_DOCUMENT_NODE)) {
+#ifdef DEBUG_STEP
+			    n++;
+#endif
+			    xmlXPathNodeSetAdd(ret, cur);
+			}
 		    }
 		    break;
                 case NODE_TEST_NS: {
-		    TODO /* namespace search */
+		    TODO;
 		    break;
 		}
                 case NODE_TEST_NAME:
@@ -2673,6 +2743,10 @@
 			    }
 			    break;
 			}
+			case XML_NAMESPACE_DECL: {
+			    TODO;
+			    break;
+			}
 			default:
 			    break;
 		    }
@@ -2720,6 +2794,7 @@
  * @ctxt:  the XPath Parser context
  *
  * Implement the last() XPath function
+ *    number last()
  * The last function returns the number of nodes in the context node list.
  */
 void
@@ -2913,6 +2988,10 @@
 	    valuePush(ctxt,
 		      xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
 	    break;
+	case XML_NAMESPACE_DECL:
+	    valuePush(ctxt, xmlXPathNewString(
+			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
+	    break;
 	default:
 	    valuePush(ctxt, xmlXPathNewCString(""));
 	}
@@ -4572,6 +4651,7 @@
 	obj2 = valuePop(ctxt);
 	obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
 		                                obj2->nodesetval);
+	valuePush(ctxt, obj1);
 	xmlXPathFreeObject(obj2);
 	SKIP_BLANKS;
     }
diff --git a/xpointer.c b/xpointer.c
index aa4b8e0..08d00b9 100644
--- a/xpointer.c
+++ b/xpointer.c
@@ -25,6 +25,7 @@
  */
 
 #include <stdio.h>
+#include <string.h>
 #include <libxml/xpointer.h>
 #include <libxml/xmlmemory.h>
 #include <libxml/parserInternals.h>
@@ -1711,8 +1712,13 @@
 		    if (node->content == NULL) {
 			return(xmlXPtrNewRange(node, 0, node, 0));
 		    } else {
+#ifndef XML_USE_BUFFER_CONTENT
 			return(xmlXPtrNewRange(node, 0, node,
 					       xmlStrlen(node->content)));
+#else
+			return(xmlXPtrNewRange(node, 0, node,
+					       xmlBufferLength(node->content)));
+#endif
 		    }
 		}
 		case XML_ATTRIBUTE_NODE:
@@ -1743,8 +1749,13 @@
 			if (node->content == NULL) {
 			    return(xmlXPtrNewRange(node, 0, node, 0));
 			} else {
+#ifndef XML_USE_BUFFER_CONTENT
 			    return(xmlXPtrNewRange(node, 0, node,
 						   xmlStrlen(node->content)));
+#else
+			    return(xmlXPtrNewRange(node, 0, node,
+					       xmlBufferLength(node->content)));
+#endif
 			}
 		    }
 		    case XML_ATTRIBUTE_NODE:
@@ -2010,7 +2021,11 @@
 	 */
 	len = 0;
 	if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
 	    len = xmlStrlen(cur->content);
+#else
+	    len = xmlBufferLength(cur->content);
+#endif
 	}
 	if (pos > len) {
 	    /* Strange, the index in the text node is greater than it's len */
@@ -2072,9 +2087,18 @@
 	if ((cur == *end) && (pos + stringlen > *endindex))
 	    return(0);
 	if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
 	    len = xmlStrlen(cur->content);
+#else
+	    len = xmlBufferLength(cur->content);
+#endif
 	    if (len >= pos + stringlen) {
+#ifndef XML_USE_BUFFER_CONTENT
 		match = (!xmlStrncmp(&cur->content[pos], string, stringlen));
+#else
+		len = (!xmlStrncmp(&xmlBufferContent(cur->content)[pos],
+			           string, stringlen));
+#endif
 		if (match) {
 #ifdef DEBUG_RANGES
 		    xmlGenericError(xmlGenericErrorContext,
@@ -2091,7 +2115,12 @@
 		}
 	    } else {
                 int sub = len - pos;
+#ifndef XML_USE_BUFFER_CONTENT
 		match = (!xmlStrncmp(&cur->content[pos], string, sub));
+#else
+		len = (!xmlStrncmp(&xmlBufferContent(cur->content)[pos],
+			           string, sub));
+#endif
 		if (match) {
 #ifdef DEBUG_RANGES
 		    xmlGenericError(xmlGenericErrorContext,
@@ -2156,12 +2185,21 @@
 
     while (cur != NULL) {
 	if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
 	    len = xmlStrlen(cur->content);
+#else
+	    len = xmlBufferLength(cur->content);
+#endif
 	    while (pos <= len) {
 		if (first != 0) {
+#ifndef XML_USE_BUFFER_CONTENT
 		    str = xmlStrchr(&cur->content[pos], first);
+#else
+		    str = xmlStrchr(&xmlBufferContent(cur->content)[pos],
+			            first);
+#endif
 		    if (str != NULL) {
-			pos = (str - cur->content);
+			pos = (str - (xmlChar *)(cur->content));
 #ifdef DEBUG_RANGES
 			xmlGenericError(xmlGenericErrorContext,
 				"found '%c' at index %d of ->",
@@ -2244,7 +2282,11 @@
 	if (cur->last != NULL)
 	    cur = cur->last;
 	else if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
 	    len = xmlStrlen(cur->content);
+#else
+	    len = xmlBufferLength(cur->content);
+#endif
 	    break;
 	}
     }
@@ -2459,7 +2501,7 @@
 					xmlXPtrNewRange(start, startindex,
 							rend, rindex));
 			}
-		    } else if (num <= 0) {
+		    } else if ((number != NULL) && (num <= 0)) {
 			xmlXPtrLocationSetAdd(newset,
 				    xmlXPtrNewRange(start, startindex,
 						    start, startindex));