Revert directory structure changes
diff --git a/xinclude.c b/xinclude.c
new file mode 100644
index 0000000..c377f64
--- /dev/null
+++ b/xinclude.c
@@ -0,0 +1,806 @@
+/*
+ * 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) {
+    int i;
+
+    if (ctxt == NULL)
+	return;
+    for (i = 0;i < ctxt->docNr;i++) {
+	xmlFreeDoc(ctxt->docTab[i]);
+	if (ctxt->urlTab[i] != NULL)
+	    xmlFree(ctxt->urlTab[i]);
+    }
+    for (i = 0;i < ctxt->txtNr;i++) {
+	if (ctxt->txturlTab[i] != NULL)
+	    xmlFree(ctxt->txturlTab[i]);
+    }
+    if (ctxt->incTab != NULL)
+	xmlFree(ctxt->incTab);
+    if (ctxt->repTab != NULL)
+	xmlFree(ctxt->repTab);
+    if (ctxt->urlTab != NULL)
+	xmlFree(ctxt->urlTab);
+    if (ctxt->docTab != NULL)
+	xmlFree(ctxt->docTab);
+    if (ctxt->txtTab != NULL)
+	xmlFree(ctxt->txtTab);
+    if (ctxt->txturlTab != NULL)
+	xmlFree(ctxt->txturlTab);
+    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;
+    xmlChar *fragment = NULL;
+    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) {
+	fragment = (xmlChar *) uri->fragment;
+	uri->fragment = NULL;
+    }
+    URL = xmlSaveUri(uri);
+    xmlFreeURI(uri);
+    if (URL == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: invalid value URI %s\n", url);
+	if (fragment != NULL)
+	    xmlFree(fragment);
+	return;
+    }
+
+    /*
+     * Handling of references to the local document are done
+     * directly through ctxt->doc.
+     */
+    if ((URL[0] == 0) || (URL[0] == '#')) {
+	doc = NULL;
+        goto loaded;
+    }
+
+    /*
+     * 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);
+	if (fragment != NULL)
+	    xmlFree(fragment);
+	return;
+    }
+    xmlXIncludeAddDoc(ctxt, doc, URL);
+
+loaded:
+    if (fragment == NULL) {
+	/*
+	 * Add the top children list as the replacement copy.
+	 * ISSUE: seems we should scrap DTD info from the copied list.
+	 */
+	if (doc == NULL)
+	    ctxt->repTab[nr] = xmlCopyNodeList(ctxt->doc->children);
+	else
+	    ctxt->repTab[nr] = xmlCopyNodeList(doc->children);
+    } else {
+	/*
+	 * Computes the XPointer expression and make a copy used
+	 * as the replacement copy.
+	 */
+	xmlXPathObjectPtr xptr;
+	xmlXPathContextPtr xptrctxt;
+
+	if (doc == NULL) {
+	    xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr], NULL);
+	} else {
+	    xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
+	}
+	if (xptrctxt == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+			"XInclude: could create XPointer context\n");
+	    xmlFree(URL);
+	    xmlFree(fragment);
+	    return;
+	}
+	xptr = xmlXPtrEval(fragment, xptrctxt);
+	if (xptr == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+			"XInclude: XPointer evaluation failed: #%s\n",
+			fragment);
+	    xmlXPathFreeContext(xptrctxt);
+	    xmlFree(URL);
+	    xmlFree(fragment);
+	    return;
+	}
+	ctxt->repTab[nr] = xmlXPtrBuildNodeList(xptr);
+	xmlXPathFreeObject(xptr);
+	xmlXPathFreeContext(xptrctxt);
+	xmlFree(fragment);
+    }
+    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) {
+	xmlGenericError(xmlGenericErrorContext,
+		"XInclude: fragment identifier forbidden for text: %s\n",
+		uri->fragment);
+	xmlFreeURI(uri);
+	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);
+    if (base == NULL) {
+	URI = xmlBuildURI(href, ctxt->doc->URL);
+    } else {
+	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