diff --git a/ChangeLog b/ChangeLog
index 7767ed7e2fe241edc922eeb2c1e167f43c8184e6_Q2hhbmdlTG9n..b3ad0d686d07b559675fb012a35d6d7a29b92491_Q2hhbmdlTG9n 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Tue Jan 14 14:23:47 CET 2003 Daniel Veillard <daniel@veillard.com>
+
+	* libxslt/functions.c: fixed #101502 by applying and cleaning up
+	  the associated patch from Daniel Stodden.
+	* tests/documents/Makefile.am tests/documents/fragment*: added a
+	  specific test.
+
 Mon Jan 13 23:25:59 CET 2003 Daniel Veillard <daniel@veillard.com>
 
 	* libxslt/extensions.c libxslt/transform.c: fixing bug #101602
diff --git a/libxslt/functions.c b/libxslt/functions.c
index 7767ed7e2fe241edc922eeb2c1e167f43c8184e6_bGlieHNsdC9mdW5jdGlvbnMuYw==..b3ad0d686d07b559675fb012a35d6d7a29b92491_bGlieHNsdC9mdW5jdGlvbnMuYw== 100644
--- a/libxslt/functions.c
+++ b/libxslt/functions.c
@@ -32,6 +32,7 @@
 #include <libxml/xpathInternals.h>
 #include <libxml/parserInternals.h>
 #include <libxml/uri.h>
+#include <libxml/xpointer.h>
 #include "xslt.h"
 #include "xsltInternals.h"
 #include "xsltutils.h"
@@ -97,6 +98,112 @@
  *									*
  ************************************************************************/
 
+static void
+xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
+{
+    xsltTransformContextPtr tctxt;
+    xmlURIPtr uri;
+    xmlChar *fragment;
+    xsltDocumentPtr xsltdoc;
+    xmlDocPtr doc;
+    xmlXPathContextPtr xptrctxt;
+    xmlXPathObjectPtr object;
+
+    tctxt = xsltXPathGetTransformContext(ctxt);
+    if (tctxt == NULL) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+			   "document() : internal error tctxt == NULL\n");
+	valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+	return;
+    } 
+	
+    uri = xmlParseURI((const char *) URI);
+    if (uri == NULL) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+			   "document() : failed to parse URI\n");
+	valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+	return;
+    } 
+    
+    /*
+     * check for and remove fragment identifier
+     */
+    fragment = uri->fragment;
+    if (fragment != NULL) {
+	uri->fragment = NULL;
+	URI = xmlSaveUri(uri);
+	xsltdoc = xsltLoadDocument(tctxt, URI);
+	xmlFree(URI);
+    } else
+	xsltdoc = xsltLoadDocument(tctxt, URI);
+    xmlFreeURI(uri);
+    
+    if (xsltdoc == NULL) {
+	if ((URI == NULL) ||
+	    (URI[0] = '#') ||
+	    (xmlStrEqual(tctxt->style->doc->URL, URI))) {
+	    doc = tctxt->style->doc;
+	} else {
+	    valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+
+	    if (fragment != NULL)
+		xmlFree(fragment);
+
+	    return;
+	}
+    }
+    doc = xsltdoc->doc;
+
+    if ( fragment == NULL ) {
+	valuePush(ctxt,
+		  xmlXPathNewNodeSet((xmlNodePtr) doc));
+	return;
+    }
+	
+    /* use XPointer of HTML location for fragment ID */
+    
+    xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
+    if (xptrctxt == NULL) {
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+			   "document() : internal error xptrctxt == NULL\n");
+	goto out_fragment;
+    }
+
+    object = xmlXPtrEval(fragment, xptrctxt);
+    xmlFree(fragment);
+    xmlXPathFreeContext(xptrctxt);
+
+    if (object == NULL)
+	goto out_fragment;
+	
+    switch (object->type) {
+    case XPATH_NODESET:
+	break;
+    case XPATH_UNDEFINED:
+    case XPATH_BOOLEAN:
+    case XPATH_NUMBER:
+    case XPATH_STRING:
+    case XPATH_POINT:
+    case XPATH_USERS:
+    case XPATH_XSLT_TREE:
+    case XPATH_RANGE:
+    case XPATH_LOCATIONSET:
+	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
+			   "document() : XPointer does not select a node set: #%s\n", 
+			   fragment);
+	goto out_object;
+    }
+    
+    valuePush(ctxt, object);
+    return;
+
+out_object:
+    xmlXPathFreeObject(object);
+
+out_fragment:
+    valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+}
+
 /**
  * xsltDocumentFunction:
  * @ctxt:  the XPath Parser context
@@ -108,7 +215,6 @@
 void
 xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
 {
-    xsltDocumentPtr doc;
     xmlXPathObjectPtr obj, obj2 = NULL;
     xmlChar *base = NULL, *URI;
 
@@ -215,32 +321,9 @@
         if (URI == NULL) {
             valuePush(ctxt, xmlXPathNewNodeSet(NULL));
         } else {
-            xsltTransformContextPtr tctxt;
-
-            tctxt = xsltXPathGetTransformContext(ctxt);
-            if (tctxt == NULL) {
-                xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
-                                 "document() : internal error tctxt == NULL\n");
-                valuePush(ctxt, xmlXPathNewNodeSet(NULL));
-            } else {
-                doc = xsltLoadDocument(tctxt, URI);
-                if (doc == NULL) {
-		    if ((xmlStrEqual(URI, BAD_CAST "")) ||
-			(xmlStrEqual(tctxt->style->doc->URL, URI))) {
-			valuePush(ctxt, xmlXPathNewNodeSet(
-				    (xmlNodePtr)tctxt->style->doc));
-		    } else {
-			valuePush(ctxt, xmlXPathNewNodeSet(NULL));
-		    }
-		} else {
-                    /* TODO: use XPointer of HTML location for fragment ID */
-                    /* pbm #xxx can lead to location sets, not nodesets :-) */
-                    valuePush(ctxt,
-                              xmlXPathNewNodeSet((xmlNodePtr) doc->doc));
-                }
-            }
-            xmlFree(URI);
-        }
+	    xsltDocumentFunctionLoadDocument( ctxt, URI );
+	    xmlFree(URI);
+	}
     }
     xmlXPathFreeObject(obj);
     if (obj2 != NULL)
diff --git a/tests/documents/Makefile.am b/tests/documents/Makefile.am
index 7767ed7e2fe241edc922eeb2c1e167f43c8184e6_dGVzdHMvZG9jdW1lbnRzL01ha2VmaWxlLmFt..b3ad0d686d07b559675fb012a35d6d7a29b92491_dGVzdHMvZG9jdW1lbnRzL01ha2VmaWxlLmFt 100644
--- a/tests/documents/Makefile.am
+++ b/tests/documents/Makefile.am
@@ -30,4 +30,8 @@
 	diff $(srcdir)/message.result result; \
 	grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0" || true;\
 	rm -f result)
+	@($(CHECKER) $(top_builddir)/xsltproc/xsltproc $(srcdir)/fragment.xsl $(srcdir)/fragment.xml > result 2>&1 ; \
+	diff $(srcdir)/fragment.result result; \
+	grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0" || true;\
+	rm -f result)
 
diff --git a/tests/documents/fragment.result b/tests/documents/fragment.result
new file mode 100644
index 0000000000000000000000000000000000000000..b3ad0d686d07b559675fb012a35d6d7a29b92491_dGVzdHMvZG9jdW1lbnRzL2ZyYWdtZW50LnJlc3VsdA==
--- /dev/null
+++ b/tests/documents/fragment.result
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<doc><p>hello</p></doc>
diff --git a/tests/documents/fragment.xml b/tests/documents/fragment.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b3ad0d686d07b559675fb012a35d6d7a29b92491_dGVzdHMvZG9jdW1lbnRzL2ZyYWdtZW50LnhtbA==
--- /dev/null
+++ b/tests/documents/fragment.xml
@@ -0,0 +1,1 @@
+<doc/>
diff --git a/tests/documents/fragment.xsl b/tests/documents/fragment.xsl
new file mode 100644
index 0000000000000000000000000000000000000000..b3ad0d686d07b559675fb012a35d6d7a29b92491_dGVzdHMvZG9jdW1lbnRzL2ZyYWdtZW50LnhzbA==
--- /dev/null
+++ b/tests/documents/fragment.xsl
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+		version="1.0">
+
+<xsl:template match="/">
+  <doc>
+    <xsl:copy-of select="document('fragment2.xml#xpointer(//p[1])')"/>
+  </doc>
+</xsl:template>
+
+</xsl:stylesheet>
+
diff --git a/tests/documents/fragment2.xml b/tests/documents/fragment2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b3ad0d686d07b559675fb012a35d6d7a29b92491_dGVzdHMvZG9jdW1lbnRzL2ZyYWdtZW50Mi54bWw=
--- /dev/null
+++ b/tests/documents/fragment2.xml
@@ -0,0 +1,3 @@
+<test><doc><p>hello</p>
+<title>foo</title>
+<p>goodbye</p></doc></test>