Re: [xslt] extension modules



Le 22/07/01 06:34:40, Thomas Broyer a écrit :
> Here's a list of some of the changes:
>   · added an extInfos field to xsltStylesheet for stylesheet module data
>   · added the couple of stylesheet data init/shutdown functions to
>     xsltExtModule (this is a private struct)
>     and a function xsltRegisterExtModuleFull that receives these 4
>     functions
>   · added xslt{Register,Unregister}ExtModule{Function,ElementTopLevel}
>     and xsltExtModule{Function,Element,ElementPreCompute,TopLevel}Lookup
>   · added function lookup framework to libxml/XPath and used it in
> libxslt
>     and modified the extension element lookup in the same way (look for
>     the element in the context, then in the global registry)
>   · modified xsltGetExtData to initialize the module when needed and
>     added xsltStyleGetExtData for the stylesheet data
>   · modified xsltInitCtxtExts to do the automatic initialization of
>     modules with stylesheet data (and do not care about
>     extension-element-prefixes)
>   · modified xsltParseTemplateContent to be independant of xsltTemplate
>     and made it public: extension elements may need it (func:function do)
>     to precompute their contents.
>   · modified xsltPrecomputeStylesheetTop to precompute top-level elements
> 
> What's still needed:
>   · correct handling of extension-element-prefixes and
>     exclude-result-prefixes. extension-element-prefixes may need binding
>     data to the _private field of *every* element node (even literal
>     result elements)
>   · actually do extension element precomputation
>   · test, test and test again...

Here's the patch, if someone wants to help. Please note that the API won't
be freezed until we stated on my message on 23/07/01 19:39:47 in this
thread about an "extension element precomputed data framework".

Also:
 · code isn't as clean as it could be => the patch can't be commited as-is
 · extension element precomputation is almost done. There's some "bug"
   for elements with a local-name equal to "document".
 · I moved the test module from functions.c to extensions.c. Other
   "extras" should also be moved to the new extension framework IMO.

Tom.
Index: libexslt/common.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/common.c,v
retrieving revision 1.4
diff -u -r1.4 common.c
--- libexslt/common.c	2001/07/16 04:56:47	1.4
+++ libexslt/common.c	2001/07/25 14:54:35
@@ -52,19 +52,6 @@
 }
 
 
-static void *
-exsltCommonInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {
-    xsltRegisterExtFunction (ctxt, (const xmlChar *) "node-set",
-			     URI, xsltFunctionNodeSet);
-    xsltRegisterExtFunction (ctxt, (const xmlChar *) "object-type",
-			     URI, exsltObjectTypeFunction);
-
-    xsltRegisterExtElement (ctxt, (const xmlChar *) "document",
-			    URI, xsltDocumentElem);
-
-    return(NULL);
-}
-
 /**
  * exsltCommonRegister:
  *
@@ -73,6 +60,13 @@
 
 void
 exsltCommonRegister (void) {
-    xsltRegisterExtModule (EXSLT_COMMON_NAMESPACE,
-			   exsltCommonInit, NULL);
+    xsltRegisterExtModuleFunction((const xmlChar *) "node-set",
+				  EXSLT_COMMON_NAMESPACE,
+				  xsltFunctionNodeSet);
+    xsltRegisterExtModuleFunction((const xmlChar *) "object-type",
+				  EXSLT_COMMON_NAMESPACE,
+				  exsltObjectTypeFunction);
+    xsltRegisterExtModuleElement((const xmlChar *) "document",
+				 EXSLT_COMMON_NAMESPACE,
+				 NULL, xsltDocumentElem);
 }
Index: libexslt/functions.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/functions.c,v
retrieving revision 1.4
diff -u -r1.4 functions.c
--- libexslt/functions.c	2001/07/16 04:56:47	1.4
+++ libexslt/functions.c	2001/07/25 14:54:35
@@ -23,13 +23,33 @@
     int error;
 };
 
-static void exsltFuncFunctionElem (xsltTransformContextPtr ctxt,
-				   xmlNodePtr node, xmlNodePtr inst,
-				   xsltStylePreCompPtr comp);
-static void exsltFuncResultElem (xsltTransformContextPtr ctxt,
-				 xmlNodePtr node, xmlNodePtr inst,
-				 xsltStylePreCompPtr comp);
 
+static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt,
+				       int nargs);
+
+/**
+ * exsltFuncRegisterFunc:
+ * @func:  the #exsltFuncFunctionData for the function
+ * @ctxt:  an XSLT transformation context
+ * @URI:  the function namespace URI
+ * @name: the function name
+ *
+ * Registers a function declared by a func:function element
+ */
+static void
+exsltFuncRegisterFunc (exsltFuncFunctionData *data,
+		       xsltTransformContextPtr ctxt,
+		       const xmlChar *URI, const xmlChar *name) {
+    if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL))
+	return;
+
+    xsltGenericDebug(xsltGenericDebugContext,
+		     "exsltFuncRegisterFunc: register {%s}%s\n",
+		     URI, name);
+    xsltRegisterExtFunction(ctxt, name, URI,
+			    exsltFuncFunctionFunction);
+}
+
 /**
  * exsltFuncInit:
  * @ctxt: an XSLT transformation context
@@ -41,6 +61,7 @@
  */
 static exsltFuncData *
 exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {
+    xmlHashTablePtr hash;
     exsltFuncData *ret;
 
     ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData));
@@ -51,15 +72,13 @@
     }
     memset(ret, 0, sizeof(exsltFuncData));
 
-    ret->funcs = xmlHashCreate(1);
     ret->result = NULL;
     ret->error = 0;
 
-    xsltRegisterExtElement (ctxt, (const xmlChar *) "function",
-			    URI, exsltFuncFunctionElem);
-    xsltRegisterExtElement (ctxt, (const xmlChar *) "result",
-			    URI, exsltFuncResultElem);
+    hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI);
+    xmlHashScanFull(hash, (xmlHashScannerFull) exsltFuncRegisterFunc, ctxt);
 
+    ret->funcs = hash;
 
     return(ret);
 }
@@ -67,7 +86,7 @@
 /**
  * exsltFuncShutdown:
  * @ctxt: an XSLT transformation context
- * @URI: the namespace URI fir the extension
+ * @URI: the namespace URI for the extension
  * @data: the module data to free up
  *
  * Shutdown the EXSLT - Functions module
@@ -76,23 +95,39 @@
 exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
 		   const xmlChar *URI ATTRIBUTE_UNUSED,
 		   exsltFuncData *data) {
-    if (data->funcs != NULL)
-	xmlHashFree(data->funcs, (xmlHashDeallocator) xmlFree);
     if (data->result != NULL)
 	xmlXPathFreeObject(data->result);
     xmlFree(data);
 }
 
 /**
- * exsltFuncRegister:
+ * exsltFuncStyleInit:
+ * @style: an XSLT stylesheet
+ * @URI: the namespace URI for the extension
  *
- * Registers the EXSLT - Functions module
+ * Allocates the styleshet data for EXSLT - Function
+ *
+ * Returns the allocated data
  */
-void
-exsltFuncRegister (void) {
-    xsltRegisterExtModule (EXSLT_FUNCTIONS_NAMESPACE,
-			   (xsltExtInitFunction) exsltFuncInit,
-			   (xsltExtShutdownFunction) exsltFuncShutdown);
+static xmlHashTablePtr
+exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
+		    const xmlChar *URI ATTRIBUTE_UNUSED) {
+    return xmlHashCreate(1);
+}
+
+/**
+ * exsltFuncStyleShutdown:
+ * @style: an XSLT stylesheet
+ * @URI: the namespace URI for the extension
+ * @data: the stylesheet data to free up
+ *
+ * Shutdown the EXSLT - Function module
+ */
+static void
+exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED,
+			const xmlChar *URI ATTRIBUTE_UNUSED,
+			xmlHashTablePtr data) {
+    xmlHashFree(data, NULL);
 }
 
 /**
@@ -112,6 +147,7 @@
 			 "exsltFuncNewFunctionData: not enough memory\n");
 	return (NULL);
     }
+    memset(ret, 0, sizeof(exsltFuncFunctionData));
 
     ret->nargs = 0;
     ret->content = NULL;
@@ -124,11 +160,12 @@
  * @ctxt:  an XPath parser context
  * @nargs:  the number of arguments
  *
- * Evaluates the func:function element defining the called function.
+ * Evaluates the func:function element that defines the called function.
  */
 static void
 exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
     xmlXPathObjectPtr obj, oldResult, ret;
+    xmlHashTablePtr funcs;
     exsltFuncData *data;
     exsltFuncFunctionData *func;
     xmlNodePtr paramNode, oldInsert, fake;
@@ -215,6 +252,7 @@
      * the generation of result nodes.
      */
     if (fake->children != NULL) {
+	xmlDebugDumpNode (stderr, fake, 1);
 	xsltGenericError(xsltGenericErrorContext,
 			 "{%s}%s: cannot write to result tree while "
 			 "executing a function\n",
@@ -224,16 +262,18 @@
     valuePush(ctxt, ret);
 }
 
+
+void xsltParseTemplateContent(xsltStylesheetPtr style,
+			      xmlNodePtr template);
+
 static void
-exsltFuncFunctionElem (xsltTransformContextPtr ctxt, xmlNodePtr node,
-		       xmlNodePtr inst, xsltStylePreCompPtr comp) {
+exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) {
     xmlChar *name, *prefix;
     xmlNsPtr ns;
-    exsltFuncData *data;
+    xmlHashTablePtr data;
     exsltFuncFunctionData *func;
-    xsltStylePreCompPtr param_comp;
 
-    if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL))
+    if ((style == NULL) || (inst == NULL))
 	return;
 
     {
@@ -267,27 +307,36 @@
      */
     func = exsltFuncNewFunctionData();
     func->content = inst->children;
-    param_comp = (xsltStylePreCompPtr) func->content->_private;
-    while ((param_comp != NULL) && (param_comp->type == XSLT_FUNC_PARAM)) {
+    while (IS_XSLT_ELEM(func->content) &&
+	   IS_XSLT_NAME(func->content, "param")) {
 	func->content = func->content->next;
 	func->nargs++;
-	param_comp = (xsltStylePreCompPtr) func->content->_private;
     }
 
+    xsltParseTemplateContent(style, inst);
+
     /*
      * Register the function data such that it can be retrieved
      * by exslFuncFunctionFunction
-     */
-    data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE);
-    xmlHashAddEntry2 (data->funcs, ns->href, name, func);
-
-    /*
-     * Register the function such that it is available for use in XPath
-     * expressions.
      */
-    xsltRegisterExtFunction (ctxt, name, ns->href,
-			     exsltFuncFunctionFunction);
+    data = (xmlHashTablePtr) xsltStyleGetExtData (style,
+						  EXSLT_FUNCTIONS_NAMESPACE);
+    if (data == NULL) {
+	xsltGenericError(xsltGenericErrorContext,
+			 "exsltFuncFunctionComp: no stylesheet data\n");
+	xmlFree(name);
+	return;
+    }
 
+    if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) {
+	xsltGenericError(xsltGenericErrorContext,
+			 "Failed to register function {%s}%s\n",
+			 ns->href, name);
+    } else {
+	xsltGenericDebug(xsltGenericDebugContext,
+			 "exsltFuncFunctionComp: register {%s}%s\n",
+			 ns->href, name);
+    }
     xmlFree(name);
 }
 
@@ -415,4 +464,26 @@
 	ret = xmlXPathNewCString("");
     }
     data->result = ret;
+}
+
+/**
+ * exsltFuncRegister:
+ *
+ * Registers the EXSLT - Functions module
+ */
+void
+exsltFuncRegister (void) {
+    xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE,
+		       (xsltExtInitFunction) exsltFuncInit,
+		       (xsltExtShutdownFunction) exsltFuncShutdown,
+		       (xsltStyleExtInitFunction) exsltFuncStyleInit,
+		       (xsltStyleExtShutdownFunction) exsltFuncStyleShutdown);
+
+    xsltRegisterExtModuleTopLevel ((const xmlChar *) "function",
+				   EXSLT_FUNCTIONS_NAMESPACE,
+				   exsltFuncFunctionComp);
+    xsltRegisterExtModuleElement ((const xmlChar *) "result",
+				  EXSLT_FUNCTIONS_NAMESPACE,
+				  NULL,
+				  exsltFuncResultElem);
 }
Index: libexslt/math.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/math.c,v
retrieving revision 1.5
diff -u -r1.5 math.c
--- libexslt/math.c	2001/07/23 00:55:42	1.5
+++ libexslt/math.c	2001/07/25 14:54:35
@@ -271,19 +271,6 @@
     xmlXPathReturnNodeSet(ctxt, ret);
 }
 
-static void *
-exsltMathInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {
-    xsltRegisterExtFunction (ctxt, (const xmlChar *) "min",
-			     URI, exsltMathMinFunction);
-    xsltRegisterExtFunction (ctxt, (const xmlChar *) "max",
-			     URI, exsltMathMaxFunction);
-    xsltRegisterExtFunction (ctxt, (const xmlChar *) "highest",
-			     URI, exsltMathHighestFunction);
-    xsltRegisterExtFunction (ctxt, (const xmlChar *) "lowest",
-			     URI, exsltMathLowestFunction);
-    return(NULL);
-}
-
 /**
  * exsltMathRegister:
  *
@@ -292,5 +279,16 @@
 
 void
 exsltMathRegister (void) {
-    xsltRegisterExtModule (EXSLT_MATH_NAMESPACE, exsltMathInit, NULL);
+    xsltRegisterExtModuleFunction ((const xmlChar *) "min",
+				   EXSLT_MATH_NAMESPACE,
+				   exsltMathMinFunction);
+    xsltRegisterExtModuleFunction ((const xmlChar *) "max",
+				   EXSLT_MATH_NAMESPACE,
+				   exsltMathMaxFunction);
+    xsltRegisterExtModuleFunction ((const xmlChar *) "highest",
+				   EXSLT_MATH_NAMESPACE,
+				   exsltMathHighestFunction);
+    xsltRegisterExtModuleFunction ((const xmlChar *) "lowest",
+				   EXSLT_MATH_NAMESPACE,
+				   exsltMathLowestFunction);
 }
Index: libexslt/sets.c
===================================================================
RCS file: /cvs/gnome/libxslt/libexslt/sets.c,v
retrieving revision 1.4
diff -u -r1.4 sets.c
--- libexslt/sets.c	2001/07/16 04:56:47	1.4
+++ libexslt/sets.c	2001/07/25 14:54:35
@@ -221,24 +221,6 @@
     xmlXPathReturnNodeSet(ctxt, ret);
 }
 
-static void *
-exsltSetsInit (xsltTransformContextPtr ctxt, const xmlChar *URI) {
-    xsltRegisterExtFunction (ctxt, (const xmlChar *) "difference",
-			     URI, exsltSetsDifferenceFunction);
-    xsltRegisterExtFunction (ctxt, (const xmlChar *) "intersection",
-			     URI, exsltSetsIntersectionFunction);
-    xsltRegisterExtFunction (ctxt, (const xmlChar *) "distinct",
-			     URI, exsltSetsDistinctFunction);
-    xsltRegisterExtFunction (ctxt, (const xmlChar *) "has-same-nodes",
-			     URI, exsltSetsHasSameNodesFunction);
-    xsltRegisterExtFunction (ctxt, (const xmlChar *) "leading",
-			     URI, exsltSetsLeadingFunction);
-    xsltRegisterExtFunction (ctxt, (const xmlChar *) "trailing",
-			     URI, exsltSetsTrailingFunction);
-
-    return(NULL);
-}
-
 /**
  * exsltCommonRegister:
  *
@@ -247,5 +229,22 @@
 
 void
 exsltSetsRegister (void) {
-    xsltRegisterExtModule (EXSLT_SETS_NAMESPACE, exsltSetsInit, NULL);
+    xsltRegisterExtModuleFunction ((const xmlChar *) "difference",
+				   EXSLT_SETS_NAMESPACE,
+				   exsltSetsDifferenceFunction);
+    xsltRegisterExtModuleFunction ((const xmlChar *) "intersection",
+				   EXSLT_SETS_NAMESPACE,
+				   exsltSetsIntersectionFunction);
+    xsltRegisterExtModuleFunction ((const xmlChar *) "distinct",
+				   EXSLT_SETS_NAMESPACE,
+				   exsltSetsDistinctFunction);
+    xsltRegisterExtModuleFunction ((const xmlChar *) "has-same-nodes",
+				   EXSLT_SETS_NAMESPACE,
+				   exsltSetsHasSameNodesFunction);
+    xsltRegisterExtModuleFunction ((const xmlChar *) "leading",
+				   EXSLT_SETS_NAMESPACE,
+				   exsltSetsLeadingFunction);
+    xsltRegisterExtModuleFunction ((const xmlChar *) "trailing",
+				   EXSLT_SETS_NAMESPACE,
+				   exsltSetsTrailingFunction);
 }
Index: libxslt/extensions.c
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/extensions.c,v
retrieving revision 1.13
diff -u -r1.13 extensions.c
--- libxslt/extensions.c	2001/07/12 01:32:04	1.13
+++ libxslt/extensions.c	2001/07/25 14:54:35
@@ -49,6 +49,8 @@
 struct _xsltExtModule {
     xsltExtInitFunction initFunc;
     xsltExtShutdownFunction shutdownFunc;
+    xsltStyleExtInitFunction styleInitFunc;
+    xsltStyleExtShutdownFunction styleShutdownFunc;
 };
 
 typedef struct _xsltExtData xsltExtData;
@@ -58,7 +60,17 @@
     void *extData;
 };
 
+typedef struct _xsltExtElement xsltExtElement;
+typedef xsltExtElement *xsltExtElementPtr;
+struct _xsltExtElement {
+    xsltPreComputeFunction precomp;
+    xsltTransformFunction  transform;
+};
+
 static xmlHashTablePtr xsltExtensionsHash = NULL;
+static xmlHashTablePtr xsltFunctionsHash = NULL;
+static xmlHashTablePtr xsltElementsHash = NULL;
+static xmlHashTablePtr xsltTopLevelsHash = NULL;
 
 /************************************************************************
  * 									*
@@ -133,6 +145,8 @@
  * xsltNewExtModule:
  * @initFunc:  the module initialization function
  * @shutdownFunc:  the module shutdown function
+ * @styleInitFunc:  the stylesheet module data allocator function
+ * @styleShutdownFunc:  the stylesheet module data free function
  *
  * Create a new XSLT extension module
  *
@@ -140,7 +154,9 @@
  */
 static xsltExtModulePtr
 xsltNewExtModule(xsltExtInitFunction initFunc,
-                 xsltExtShutdownFunction shutdownFunc)
+                 xsltExtShutdownFunction shutdownFunc,
+		 xsltStyleExtInitFunction styleInitFunc,
+		 xsltStyleExtShutdownFunction styleShutdownFunc)
 {
     xsltExtModulePtr cur;
 
@@ -153,6 +169,8 @@
     }
     cur->initFunc = initFunc;
     cur->shutdownFunc = shutdownFunc;
+    cur->styleInitFunc = styleInitFunc;
+    cur->styleShutdownFunc = styleShutdownFunc;
     return (cur);
 }
 
@@ -210,6 +228,49 @@
     xmlFree(ext);
 }
 
+/**
+ * xsltNewExtElement:
+ * @precomp:  the pre-computation function
+ * @transform:  the transformation function
+ *
+ * Create a new XSLT extension element
+ *
+ * Returns the newly allocated xsltExtElementPtr or NULL in case of
+ * error
+ */
+static xsltExtElementPtr
+xsltNewExtElement (xsltPreComputeFunction precomp,
+		   xsltTransformFunction transform) {
+    xsltExtElementPtr cur;
+
+    if (transform == NULL)
+	return(NULL);
+
+    cur = (xsltExtElementPtr) xmlMalloc(sizeof(xsltExtElement));
+    if (cur == NULL) {
+	xsltPrintErrorContext(NULL, NULL, NULL);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltNewExtElement : malloc failed\n");
+        return (NULL);
+    }
+    cur->precomp = precomp;
+    cur->transform = transform;
+    return(cur);
+}
+
+/**
+ * xsltFreeExtElement:
+ * @ext: an XSLT extension element
+ *
+ * Frees up the memory allocated by @ext
+ */
+static void
+xsltFreeExtElement (xsltExtElementPtr ext) {
+    if (ext == NULL)
+	return;
+    xmlFree(ext);
+}
+
 
 /************************************************************************
  * 									*
@@ -290,6 +351,8 @@
     }
     if (ctxt->extFunctions == NULL)
 	ctxt->extFunctions = xmlHashCreate(10);
+    if (ctxt->extFunctions == NULL)
+	return(-1);
     return(xmlHashAddEntry2(ctxt->extFunctions, name, URI, (void *) function));
 }
 
@@ -312,6 +375,8 @@
 	return(-1);
     if (ctxt->extElements == NULL)
 	ctxt->extElements = xmlHashCreate(10);
+    if (ctxt->extElements == NULL)
+	return(-1);
     return(xmlHashAddEntry2(ctxt->extElements, name, URI, (void *) function));
 }
 
@@ -330,6 +395,71 @@
 }
 
 /**
+ * xsltStyleGetExtData:
+ * @style: an XSLT stylesheet
+ * @URI:  the URI associated to the exension module
+ *
+ * Retrieve the data associated to the extension module in this given
+ * stylesheet.
+ *
+ * Returns the pointer or NULL if not present
+ */
+void *
+xsltStyleGetExtData(xsltStylesheetPtr style, const xmlChar * URI) {
+    xsltExtDataPtr data;
+
+    if ((style == NULL) || (URI == NULL))
+        return (NULL);
+    if (style->extInfos == NULL) {
+	style->extInfos = xmlHashCreate(10);
+	if (style->extInfos == NULL)
+	    return(NULL);
+	data = NULL;
+    } else {
+	data = (xsltExtDataPtr) xmlHashLookup(style->extInfos, URI);
+    }
+    if (data == NULL) {
+	void *extData;
+	xsltExtModulePtr module;
+
+	module = xmlHashLookup(xsltExtensionsHash, URI);
+	if (module == NULL) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	    xsltGenericDebug(xsltGenericDebugContext,
+			     "Not registered extension module: %s\n", URI);
+#endif
+	    return(NULL);
+	} else {
+	    if (module->styleInitFunc == NULL)
+		return(NULL);
+
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	    xsltGenericDebug(xsltGenericDebugContext,
+			     "Initializing module: %s\n", URI);
+#endif
+
+	    extData = module->styleInitFunc(style, URI);
+	    if (extData == NULL)
+		return(NULL);
+
+	    data = xsltNewExtData(module, extData);
+	    if (data == NULL)
+		return (NULL);
+	    if (xmlHashAddEntry(style->extInfos, URI,
+				(void *) data) < 0) {
+		xsltGenericError(xsltGenericErrorContext,
+				 "Failed to register module data: %s\n", URI);
+		if (module->styleShutdownFunc)
+		    module->styleShutdownFunc(style, URI, extData);
+		xsltFreeExtData(data);
+		return(NULL);
+	    }
+	}
+    }
+    return (data->extData);
+}
+
+/**
  * xsltGetExtData:
  * @ctxt: an XSLT transformation context
  * @URI:  the URI associated to the exension module
@@ -340,35 +470,149 @@
  * Returns the pointer or NULL if not present
  */
 void *
-xsltGetExtData(xsltTransformContextPtr ctxt, const xmlChar * URI)
-{
+xsltGetExtData(xsltTransformContextPtr ctxt, const xmlChar * URI) {
     xsltExtDataPtr data;
 
-    if ((ctxt == NULL) || (ctxt->extInfos == NULL) || (URI == NULL))
-        return (NULL);
-    data = (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos, URI);
-    if (data == NULL)
+    if ((ctxt == NULL) || (URI == NULL))
         return (NULL);
+    if (ctxt->extInfos == NULL) {
+	ctxt->extInfos = xmlHashCreate(10);
+	if (ctxt->extInfos == NULL)
+	    return(NULL);
+	data = NULL;
+    } else {
+	data = (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos, URI);
+    }
+    if (data == NULL) {
+	void *extData;
+	xsltExtModulePtr module;
+
+	module = xmlHashLookup(xsltExtensionsHash, URI);
+	if (module == NULL) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	    xsltGenericDebug(xsltGenericDebugContext,
+			     "Not registered extension module: %s\n", URI);
+#endif
+	    return(NULL);
+	} else {
+	    if (module->initFunc == NULL)
+		return(NULL);
+
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	    xsltGenericDebug(xsltGenericDebugContext,
+			     "Initializing module: %s\n", URI);
+#endif
+
+	    extData = module->initFunc(ctxt, URI);
+	    if (extData == NULL)
+		return(NULL);
+
+	    data = xsltNewExtData(module, extData);
+	    if (data == NULL)
+		return (NULL);
+	    if (xmlHashAddEntry(ctxt->extInfos, URI,
+				(void *) data) < 0) {
+		xsltPrintErrorContext(ctxt, NULL, NULL);
+		xsltGenericError(xsltGenericErrorContext,
+				 "Failed to register module data: %s\n", URI);
+		if (module->shutdownFunc)
+		    module->shutdownFunc(ctxt, URI, extData);
+		xsltFreeExtData(data);
+		return(NULL);
+	    }
+	}
+    }
     return (data->extData);
 }
 
+typedef struct _xsltInitExtCtxt xsltInitExtCtxt;
+struct _xsltInitExtCtxt {
+    xsltTransformContextPtr ctxt;
+    int ret;
+};
+
+/**
+ * xsltInitCtxtExt:
+ * @styleData:  the registered stylesheet data for the module
+ * @ctxt:  the XSLT transformation context + the return value
+ * @URI:  the extension URI
+ *
+ * Initializes an extension module
+ */
+static void
+xsltInitCtxtExt (xsltExtDataPtr styleData, xsltInitExtCtxt *ctxt,
+		 const xmlChar *URI) {
+    xsltExtModulePtr module;
+    xsltExtDataPtr ctxtData;
+    void *extData;
+
+    if ((styleData == NULL) || (ctxt == NULL) || (URI == NULL) ||
+	(ctxt->ret == -1)) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+    xsltGenericDebug(xsltGenericDebugContext,
+		     "xsltInitCtxtExt: NULL param or error\n");
+#endif
+        return;
+    }
+    module = styleData->extModule;
+    if ((module == NULL) || (module->initFunc == NULL)) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	xsltGenericDebug(xsltGenericDebugContext,
+			 "xsltInitCtxtExt: no module or no initFunc\n");
+#endif
+        return;
+    }
+
+    extData = module->initFunc(ctxt->ctxt, URI);
+    if (extData == NULL) {
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+	xsltGenericDebug(xsltGenericDebugContext,
+			 "xsltInitCtxtExt: no extData\n");
+#endif
+	return;
+    }
+    ctxtData = xsltNewExtData(module, extData);
+    if (ctxtData == NULL) {
+	ctxt->ret = -1;
+	return;
+    }
+
+    if (ctxt->ctxt->extInfos == NULL)
+	ctxt->ctxt->extInfos = xmlHashCreate(10);
+    if (ctxt->ctxt->extInfos == NULL) {
+	ctxt->ret = -1;
+	return;
+    }
+
+    if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) {
+	xsltGenericError(xsltGenericErrorContext,
+			 "Failed to register module data: %s\n", URI);
+	if (module->shutdownFunc)
+	    module->shutdownFunc(ctxt->ctxt, URI, extData);
+	xsltFreeExtData(ctxtData);
+	ctxt->ret = -1;
+	return;
+    }
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+    xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n",
+		     URI);
+#endif
+    ctxt->ret++;
+}
+
 /**
  * xsltInitCtxtExts:
  * @ctxt: an XSLT transformation context
  *
- * Initialize the set of modules associated to the extension prefixes
+ * Initialize the set of modules with registered stylesheet data
  *
  * Returns the number of modules initialized or -1 in case of error
  */
 int
 xsltInitCtxtExts(xsltTransformContextPtr ctxt)
 {
-    int ret = 0;
     xsltStylesheetPtr style;
-    xsltExtDefPtr def;
-    xsltExtModulePtr module;
-    xsltExtDataPtr data;
-    void *extData;
+    xsltInitExtCtxt ctx;
 
     if (ctxt == NULL)
         return (-1);
@@ -376,71 +620,24 @@
     style = ctxt->style;
     if (style == NULL)
         return (-1);
+
+    ctx.ctxt = ctxt;
+    ctx.ret = 0;
+
     while (style != NULL) {
-        def = (xsltExtDefPtr) style->nsDefs;
-        while (def != NULL) {
-            if (def->URI != NULL) {
-                if (ctxt->extInfos == NULL) {
-                    ctxt->extInfos = xmlHashCreate(10);
-                    if (ctxt->extInfos == NULL)
-                        return (-1);
-                    data = NULL;
-                } else {
-                    data =
-                        (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos,
-                                                       def->URI);
-                }
-                if (data == NULL) {
-                    /*
-                     * Register this module
-                     */
-                    module = xmlHashLookup(xsltExtensionsHash, def->URI);
-                    if (module == NULL) {
-#ifdef WITH_XSLT_DEBUG_EXTENSIONS
-                        xsltGenericDebug(xsltGenericDebugContext,
-				     "Not registered extension module : %s\n",
-                                         def->URI);
-#endif
-                    } else {
-                        if (module->initFunc != NULL) {
-#ifdef WITH_XSLT_DEBUG_EXTENSIONS
-                            xsltGenericDebug(xsltGenericDebugContext,
-                                             "Initializing module : %s\n",
-                                             def->URI);
-#endif
-                            extData = module->initFunc(ctxt, def->URI);
-                        } else {
-                            extData = NULL;
-                        }
-                        data = xsltNewExtData(module, extData);
-                        if (data == NULL)
-                            return (-1);
-                        if (xmlHashAddEntry(ctxt->extInfos, def->URI,
-                                            (void *) data) < 0) {
-			    xsltPrintErrorContext(ctxt, NULL, NULL);
-                            xsltGenericError(xsltGenericErrorContext,
-                                             "Failed to register module : %s\n",
-                                             def->URI);
-                        } else {
-			    ret++;
-#ifdef WITH_XSLT_DEBUG_EXTENSIONS
-                        xsltGenericDebug(xsltGenericDebugContext,
-                                         "Registered module : %s\n",
-                                         def->URI);
-#endif
-			}
-
-                    }
-                }
-            }
-            def = def->next;
-        }
+	if (style->extInfos != NULL) {
+	    xmlHashScan(style->extInfos,
+			(xmlHashScanner) xsltInitCtxtExt, &ctx);
+	    if (ctx.ret == -1)
+		return(-1);
+	}
         style = xsltNextImport(style);
     }
 #ifdef WITH_XSLT_DEBUG_EXTENSIONS
-    xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n", ret);
+    xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n",
+		     ctx.ret);
 #endif
-    return (ret);
+    return (ctx.ret);
 }
 
 /**
@@ -491,6 +688,53 @@
 }
 
 /**
+ * xsltShutdownExt:
+ * @data:  the registered data for the module
+ * @ctxt:  the XSLT stylesheet
+ * @URI:  the extension URI
+ *
+ * Shutdown an extension module loaded
+ */
+static void
+xsltShutdownExt(xsltExtDataPtr data, xsltStylesheetPtr style,
+		const xmlChar * URI)
+{
+    xsltExtModulePtr module;
+
+    if ((data == NULL) || (style == NULL) || (URI == NULL))
+        return;
+    module = data->extModule;
+    if ((module == NULL) || (module->styleShutdownFunc == NULL))
+        return;
+
+#ifdef WITH_XSLT_DEBUG_EXTENSIONS
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "Shutting down module : %s\n", URI);
+#endif
+    module->styleShutdownFunc(style, URI, data->extData);
+    xmlHashRemoveEntry(style->extInfos, URI,
+                       (xmlHashDeallocator) xsltFreeExtData);
+}
+
+/**
+ * xsltShutdownExts:
+ * @style: an XSLT stylesheet
+ *
+ * Shutdown the set of modules loaded
+ */
+void
+xsltShutdownExts(xsltStylesheetPtr style)
+{
+    if (style == NULL)
+	return;
+    if (style->extInfos == NULL)
+	return;
+    xmlHashScan(style->extInfos, (xmlHashScanner) xsltShutdownExt, style);
+    xmlHashFree(style->extInfos, (xmlHashDeallocator) xsltFreeExtData);
+    style->extInfos = NULL;
+}
+
+/**
  * xsltCheckExtPrefix:
  * @style: the stylesheet
  * @prefix: the namespace prefix (possibly NULL)
@@ -516,19 +760,23 @@
 }
 
 /**
- * xsltRegisterExtModule:
+ * xsltRegisterExtModuleFull:
  * @URI:  URI associated to this module
  * @initFunc:  the module initialization function
  * @shutdownFunc:  the module shutdown function
+ * @styleInitFunc:  the module initialization function
+ * @styleShutdownFunc:  the module shutdown function
  *
  * Register an XSLT extension module to the library.
  *
  * Returns 0 if sucessful, -1 in case of error
  */
 int
-xsltRegisterExtModule(const xmlChar * URI,
-                      xsltExtInitFunction initFunc,
-                      xsltExtShutdownFunction shutdownFunc)
+xsltRegisterExtModuleFull(const xmlChar * URI,
+			  xsltExtInitFunction initFunc,
+			  xsltExtShutdownFunction shutdownFunc,
+			  xsltStyleExtInitFunction styleInitFunc,
+			  xsltStyleExtShutdownFunction styleShutdownFunc)
 {
     int ret;
     xsltExtModulePtr module;
@@ -548,7 +796,8 @@
             return (0);
         return (-1);
     }
-    module = xsltNewExtModule(initFunc, shutdownFunc);
+    module = xsltNewExtModule(initFunc, shutdownFunc,
+			      styleInitFunc, styleShutdownFunc);
     if (module == NULL)
         return (-1);
     ret = xmlHashAddEntry(xsltExtensionsHash, URI, (void *) module);
@@ -556,6 +805,24 @@
 }
 
 /**
+ * xsltRegisterExtModule:
+ * @URI:  URI associated to this module
+ * @initFunc:  the module initialization function
+ * @shutdownFunc:  the module shutdown function
+ *
+ * Register an XSLT extension module to the library.
+ *
+ * Returns 0 if sucessful, -1 in case of error
+ */
+int
+xsltRegisterExtModule(const xmlChar * URI,
+		      xsltExtInitFunction initFunc,
+		      xsltExtShutdownFunction shutdownFunc) {
+    return xsltRegisterExtModuleFull(URI, initFunc, shutdownFunc,
+				     NULL, NULL);
+}
+
+/**
  * xsltUnregisterExtModule:
  * @URI:  URI associated to this module
  *
@@ -614,4 +881,552 @@
     return(ctxt->context->extra);
 }
 
+/**
+ * xsltRegisterExtModuleFunction:
+ * @name:  the function name
+ * @URI:  the function namespace URI
+ * @function:  the function callback
+ *
+ * Registers an extension module function.
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltRegisterExtModuleFunction (const xmlChar *name, const xmlChar *URI,
+			       xmlXPathFunction function) {
+    if ((name == NULL) || (URI == NULL) || (function == NULL))
+	return(-1);
+
+    if (xsltFunctionsHash == NULL)
+	xsltFunctionsHash = xmlHashCreate(10);
+    if (xsltFunctionsHash == NULL)
+	return(-1);
+
+    xmlHashUpdateEntry2(xsltFunctionsHash, name, URI,
+			(void *) function, NULL);
+
+    return(0);
+}
+
+/**
+ * xsltExtModuleFunctionLookup:
+ * @name:  the function name
+ * @URI:  the function namespace URI
+ *
+ * Looks up an extension module function
+ *
+ * Returns the function if found, NULL otherwise.
+ */
+xmlXPathFunction
+xsltExtModuleFunctionLookup (const xmlChar *name, const xmlChar *URI) {
+    if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
+	return(NULL);
+
+    return (xmlXPathFunction) xmlHashLookup2(xsltFunctionsHash, name, URI);
+}
+
+/**
+ * xsltUnregisterExtModuleFunction:
+ * @name:  the function name
+ * @URI:  the function namespace URI
+ *
+ * Unregisters an extension module function
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltUnregisterExtModuleFunction (const xmlChar *name,
+				 const xmlChar *URI) {
+    if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL))
+	return(-1);
+
+    return xmlHashRemoveEntry2 (xsltFunctionsHash, name, URI, NULL);
+}
+
+/**
+ * xsltRegisterExtModuleElement:
+ * @name:  the element name
+ * @URI:  the element namespace URI
+ * @precomp:  the pre-computation callback
+ * @transform:  the transformation callback
+ *
+ * Registers an extension module element.
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltRegisterExtModuleElement (const xmlChar *name, const xmlChar *URI,
+			      xsltPreComputeFunction precomp,
+			      xsltTransformFunction transform) {
+    xsltExtElementPtr ext;
+
+    if ((name == NULL) || (URI == NULL) || (transform == NULL))
+	return(-1);
+
+    if (xsltElementsHash == NULL)
+	xsltElementsHash = xmlHashCreate(10);
+    if (xsltElementsHash == NULL)
+	return(-1);
 
+    ext = xsltNewExtElement(precomp, transform);
+    if (ext == NULL)
+	return(-1);
+
+    xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext,
+			(xmlHashDeallocator) xsltFreeExtElement);
+
+    return(0);
+}
+
+/**
+ * xsltExtElementLookup:
+ * @ctxt:  an XSLT process context
+ * @name:  the element name
+ * @URI:  the element namespace URI
+ *
+ * Looks up an extension element. @ctxt can be NULL to search only in
+ * module elements.
+ *
+ * Returns the element callback or NULL if not found
+ */
+xsltTransformFunction
+xsltExtElementLookup (xsltTransformContextPtr ctxt,
+		      const xmlChar *name, const xmlChar *URI) {
+    xsltTransformFunction ret;
+
+    if ((name == NULL) || (URI == NULL))
+	return(NULL);
+
+    if ((ctxt != NULL) && (ctxt->extElements != NULL)) {
+	ret = (xsltTransformFunction)
+	    xmlHashLookup2(ctxt->extElements, name, URI);
+	if (ret != NULL)
+	    return(ret);
+    }
+    return xsltExtModuleElementLookup(name, URI);
+}
+
+/**
+ * xsltExtModuleElementLookup:
+ * @name:  the element name
+ * @URI:  the element namespace URI
+ *
+ * Looks up an extension module element
+ *
+ * Returns the callback function if found, NULL otherwise.
+ */
+xsltTransformFunction
+xsltExtModuleElementLookup (const xmlChar *name, const xmlChar *URI) {
+    xsltExtElementPtr ext;
+
+    if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
+	return(NULL);
+
+    ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
+
+    if (ext == NULL)
+	return(NULL);
+    return(ext->transform);
+}
+
+/**
+ * xsltExtModuleElementPreComputeLookup:
+ * @name:  the element name
+ * @URI:  the element namespace URI
+ *
+ * Looks up an extension module element pre-computation function
+ *
+ * Returns the callback function if found, NULL otherwise.
+ */
+xsltPreComputeFunction
+xsltExtModuleElementPreComputeLookup (const xmlChar *name,
+				      const xmlChar *URI) {
+    xsltExtElementPtr ext;
+
+    if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
+	return(NULL);
+
+    ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
+
+    if (ext == NULL)
+	return(NULL);
+    return(ext->precomp);
+}
+
+/**
+ * xsltUnregisterExtModuleElement:
+ * @name:  the element name
+ * @URI:  the element namespace URI
+ *
+ * Unregisters an extension module element
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltUnregisterExtModuleElement (const xmlChar *name,
+				const xmlChar *URI) {
+    if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL))
+	return(-1);
+
+    return xmlHashRemoveEntry2 (xsltElementsHash, name, URI,
+				(xmlHashDeallocator) xsltFreeExtElement);
+}
+
+/**
+ * xsltRegisterExtModuleTopLevel:
+ * @name:  the top-level element name
+ * @URI:  the top-level element namespace URI
+ * @function:  the top-level element callback
+ *
+ * Registers an extension module top-level element.
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltRegisterExtModuleTopLevel (const xmlChar *name, const xmlChar *URI,
+			       xsltPreComputeFunction function) {
+    if ((name == NULL) || (URI == NULL) || (function == NULL))
+	return(-1);
+
+    if (xsltTopLevelsHash == NULL)
+	xsltTopLevelsHash = xmlHashCreate(10);
+    if (xsltTopLevelsHash == NULL)
+	return(-1);
+
+    xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI,
+			(void *) function, NULL);
+
+    return(0);
+}
+
+/**
+ * xsltExtModuleTopLevelLookup:
+ * @name:  the top-level element name
+ * @URI:  the top-level element namespace URI
+ *
+ * Looks up an extension module top-level element
+ *
+ * Returns the callback function if found, NULL otherwise.
+ */
+xsltPreComputeFunction
+xsltExtModuleTopLevelLookup (const xmlChar *name, const xmlChar *URI) {
+    if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
+	return(NULL);
+
+    return xmlHashLookup2(xsltTopLevelsHash, name, URI);
+}
+
+/**
+ * xsltUnregisterExtModuleTopLevel:
+ * @name:  the top-level element name
+ * @URI:  the top-level element namespace URI
+ *
+ * Unregisters an extension module top-level element
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+xsltUnregisterExtModuleTopLevel (const xmlChar *name,
+				 const xmlChar *URI) {
+    if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL))
+	return(-1);
+
+    return xmlHashRemoveEntry2 (xsltTopLevelsHash, name, URI, NULL);
+}
+
+
+/************************************************************************
+ * 									*
+ * 		Test module http://xmlsoft.org/XSLT/			*
+ * 									*
+ ************************************************************************/
+
+/************************************************************************
+ * 									*
+ * 		Test of the extension module API			*
+ * 									*
+ ************************************************************************/
+
+static xmlChar *testData = NULL;
+static xmlChar *testStyleData = NULL;
+
+/**
+ * xsltExtFunctionTest:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * function libxslt:test() for testing the extensions support.
+ */
+static void
+xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, int nargs)
+{
+    xsltTransformContextPtr tctxt;
+    void *data;
+
+    tctxt = xsltXPathGetTransformContext(ctxt);
+
+    if (testData == NULL) {
+        xsltGenericDebug(xsltGenericDebugContext,
+                         "xsltExtFunctionTest: not initialized,"
+			 " calling xsltGetExtData\n");
+	data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
+	if (data == NULL) {
+	    xsltPrintErrorContext(tctxt, NULL, NULL);
+	    xsltGenericError(xsltGenericErrorContext,
+			     "xsltExtElementTest: not initialized\n");
+	    return;
+	}
+    }
+    if (tctxt == NULL) {
+	xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtFunctionTest: failed to get the transformation context\n");
+        return;
+    }
+    if (data == NULL)
+	data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
+    if (data == NULL) {
+	xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtFunctionTest: failed to get module data\n");
+        return;
+    }
+    if (data != testData) {
+	xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtFunctionTest: got wrong module data\n");
+        return;
+    }
+#ifdef WITH_XSLT_DEBUG_FUNCTION
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "libxslt:test() called with %d args\n", nargs);
+#endif
+}
+
+/**
+ * xsltExtElementPreCompTest:
+ * @style:  the stylesheet
+ * @inst:  the instruction in the stylesheet
+ *
+ * Process a libxslt:test node
+ */
+static void
+xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst) {
+    if (style == NULL) {
+	xsltPrintErrorContext(NULL, NULL, inst);
+        xsltGenericError(xsltGenericErrorContext,
+		 "xsltExtElementTest: no transformation context\n");
+        return;
+    }
+    if (testStyleData == NULL) {
+        xsltGenericDebug(xsltGenericDebugContext,
+		 "xsltExtElementPreCompTest: not initialized,"
+		 " calling xsltStyleGetExtData\n");
+	xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL);
+	if (testStyleData == NULL) {
+	    xsltPrintErrorContext(NULL, NULL, inst);
+	    xsltGenericError(xsltGenericErrorContext,
+		 "xsltExtElementPreCompTest: not initialized\n");
+	    style->errors++;
+	    return;
+	}
+    }
+    if (inst == NULL) {
+	xsltPrintErrorContext(NULL, NULL, inst);
+        xsltGenericError(xsltGenericErrorContext,
+		 "xsltExtElementPreCompTest: no instruction\n");
+	style->errors++;
+        return;
+    }
+}
+
+/**
+ * xsltExtElementTest:
+ * @ctxt:  an XSLT processing context
+ * @node:  The current node
+ * @inst:  the instruction in the stylesheet
+ * @comp:  precomputed informations
+ *
+ * Process a libxslt:test node
+ */
+static void
+xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
+                   xmlNodePtr inst,
+                   xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
+{
+    xmlNodePtr comment;
+
+    if (testData == NULL) {
+        xsltGenericDebug(xsltGenericDebugContext,
+                         "xsltExtElementTest: not initialized,"
+			 " calling xsltGetExtData\n");
+	xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL);
+	if (testData == NULL) {
+	    xsltPrintErrorContext(ctxt, NULL, inst);
+	    xsltGenericError(xsltGenericErrorContext,
+			     "xsltExtElementTest: not initialized\n");
+	    return;
+	}
+    }
+    if (ctxt == NULL) {
+	xsltPrintErrorContext(ctxt, NULL, inst);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtElementTest: no transformation context\n");
+        return;
+    }
+    if (node == NULL) {
+	xsltPrintErrorContext(ctxt, NULL, inst);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtElementTest: no current node\n");
+        return;
+    }
+    if (inst == NULL) {
+	xsltPrintErrorContext(ctxt, NULL, inst);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtElementTest: no instruction\n");
+        return;
+    }
+    if (ctxt->insert == NULL) {
+	xsltPrintErrorContext(ctxt, NULL, inst);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtElementTest: no insertion point\n");
+        return;
+    }
+    comment =
+        xmlNewComment((const xmlChar *)
+                      "libxslt:test element test worked");
+    xmlAddChild(ctxt->insert, comment);
+}
+
+/**
+ * xsltExtInitTest:
+ * @ctxt:  an XSLT transformation context
+ * @URI:  the namespace URI for the extension
+ *
+ * A function called at initialization time of an XSLT extension module
+ *
+ * Returns a pointer to the module specific data for this transformation
+ */
+static void *
+xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI) {
+    if (testStyleData == NULL) {
+        xsltGenericDebug(xsltGenericErrorContext,
+                         "xsltExtInitTest: not initialized,"
+			 " calling xsltStyleGetExtData\n");
+	xsltStyleGetExtData(ctxt->style, URI);
+	if (testStyleData == NULL) {
+	    xsltPrintErrorContext(ctxt, NULL, NULL);
+	    xsltGenericError(xsltGenericErrorContext,
+			     "xsltExtInitTest: not initialized\n");
+	    return (NULL);
+	}
+    }	
+    if (testData != NULL) {
+	xsltPrintErrorContext(ctxt, NULL, NULL);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtInitTest: already initialized\n");
+        return (NULL);
+    }
+    testData = (void *) "test data";
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "Registered test module : %s\n", URI);
+    return (testData);
+}
+
+
+/**
+ * xsltExtShutdownTest:
+ * @ctxt:  an XSLT transformation context
+ * @URI:  the namespace URI for the extension
+ * @data:  the data associated to this module
+ *
+ * A function called at shutdown time of an XSLT extension module
+ */
+static void
+xsltExtShutdownTest(xsltTransformContextPtr ctxt,
+                    const xmlChar * URI, void *data) {
+    if (testData == NULL) {
+	xsltPrintErrorContext(ctxt, NULL, NULL);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtShutdownTest: not initialized\n");
+        return;
+    }
+    if (data != testData) {
+	xsltPrintErrorContext(ctxt, NULL, NULL);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtShutdownTest: wrong data\n");
+    }
+    testData = NULL;
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "Unregistered test module : %s\n", URI);
+}
+/**
+ * xsltExtStyleInitTest:
+ * @style:  an XSLT stylesheet
+ * @URI:  the namespace URI for the extension
+ *
+ * A function called at initialization time of an XSLT extension module
+ *
+ * Returns a pointer to the module specific data for this transformation
+ */
+static void *
+xsltExtStyleInitTest(xsltStylesheetPtr style, const xmlChar * URI)
+{
+    if (testStyleData != NULL) {
+	xsltPrintErrorContext(NULL, NULL, NULL);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtInitTest: already initialized\n");
+        return (NULL);
+    }
+    testStyleData = (void *) "test data";
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "Registered test module : %s\n", URI);
+    return (testStyleData);
+}
+
+
+/**
+ * xsltExtStyleShutdownTest:
+ * @style:  an XSLT stylesheet
+ * @URI:  the namespace URI for the extension
+ * @data:  the data associated to this module
+ *
+ * A function called at shutdown time of an XSLT extension module
+ */
+static void
+xsltExtStyleShutdownTest(xsltStylesheetPtr style,
+			 const xmlChar * URI, void *data) {
+    if (testStyleData == NULL) {
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtShutdownTest: not initialized\n");
+        return;
+    }
+    if (data != testStyleData) {
+	xsltPrintErrorContext(NULL, NULL, NULL);
+        xsltGenericError(xsltGenericErrorContext,
+                         "xsltExtShutdownTest: wrong data\n");
+    }
+    testStyleData = NULL;
+    xsltGenericDebug(xsltGenericDebugContext,
+                     "Unregistered test module : %s\n", URI);
+}
+
+/**
+ * xsltRegisterTestModule:
+ *
+ * Registers the test module
+ */
+void
+xsltRegisterTestModule (void) {
+    xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL,
+			      xsltExtInitTest, xsltExtShutdownTest,
+			      xsltExtStyleInitTest,
+			      xsltExtStyleShutdownTest);
+    xsltRegisterExtModuleFunction((const xmlChar *) "test",
+                            (const xmlChar *) XSLT_DEFAULT_URL,
+                            xsltExtFunctionTest);
+    xsltRegisterExtModuleElement((const xmlChar *) "test",
+				 (const xmlChar *) XSLT_DEFAULT_URL,
+				 xsltExtElementPreCompTest ,
+				 xsltExtElementTest);
+}
Index: libxslt/extensions.h
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/extensions.h,v
retrieving revision 1.6
diff -u -r1.6 extensions.h
--- libxslt/extensions.h	2001/07/04 13:22:39	1.6
+++ libxslt/extensions.h	2001/07/25 14:54:35
@@ -21,6 +21,30 @@
  */
 
 /**
+ * xsltStyleExtInitFunction:
+ * @ctxt:  an XSLT stylesheet
+ * @URI:  the namespace URI for the extension
+ *
+ * A function called at initialization time of an XSLT extension module
+ *
+ * Returns a pointer to the module specific data for this transformation
+ */
+typedef void * (*xsltStyleExtInitFunction)	(xsltStylesheetPtr style,
+						 const xmlChar *URI);
+
+/**
+ * xsltStyleExtShutdownFunction:
+ * @ctxt:  an XSLT stylesheet
+ * @URI:  the namespace URI for the extension
+ * @data:  the data associated to this module
+ *
+ * A function called at shutdown time of an XSLT extension module
+ */
+typedef void (*xsltStyleExtShutdownFunction)	(xsltStylesheetPtr style,
+						 const xmlChar *URI,
+						 void *data);
+
+/**
  * xsltExtInitFunction:
  * @ctxt:  an XSLT transformation context
  * @URI:  the namespace URI for the extension
@@ -47,6 +71,12 @@
 int		xsltRegisterExtModule	(const xmlChar *URI,
 					 xsltExtInitFunction initFunc,
 					 xsltExtShutdownFunction shutdownFunc);
+int		xsltRegisterExtModuleFull
+				(const xmlChar * URI,
+				 xsltExtInitFunction initFunc,
+				 xsltExtShutdownFunction shutdownFunc,
+				 xsltStyleExtInitFunction styleInitFunc,
+				 xsltStyleExtShutdownFunction styleShutdownFunc);
 
 int		xsltUnregisterExtModule	(const xmlChar * URI);
 
@@ -55,16 +85,76 @@
 void *		xsltGetExtData		(xsltTransformContextPtr ctxt,
 					 const xmlChar *URI);
 
+void *		xsltStyleGetExtData	(xsltStylesheetPtr style,
+					 const xmlChar *URI);
+
 void		xsltShutdownCtxtExts	(xsltTransformContextPtr ctxt);
 
+void		xsltShutdownExts	(xsltStylesheetPtr style);
+
 xsltTransformContextPtr
     		xsltXPathGetTransformContext
 					(xmlXPathParserContextPtr ctxt);
 
+/*
+ * extension functions
+*/
+int	xsltRegisterExtModuleFunction	(const xmlChar *name,
+					 const xmlChar *URI,
+					 xmlXPathFunction function);
+xmlXPathFunction
+	xsltExtFunctionLookup		(xsltTransformContextPtr ctxt,
+					 const xmlChar *name,
+					 const xmlChar *URI);
+xmlXPathFunction
+	xsltExtModuleFunctionLookup	(const xmlChar *name,
+					 const xmlChar *URI);
+int	xsltUnregisterExtModuleFunction	(const xmlChar *name,
+					 const xmlChar *URI);
+
+/*
+ * extension elements
+ */
+typedef void
+	(*xsltPreComputeFunction)	(xsltStylesheetPtr ctxt,
+					 xmlNodePtr inst);
+
+int	xsltRegisterExtModuleElement	(const xmlChar *name,
+					 const xmlChar *URI,
+					 xsltPreComputeFunction precomp,
+					 xsltTransformFunction transform);
+xsltTransformFunction
+	xsltExtElementLookup		(xsltTransformContextPtr ctxt,
+					 const xmlChar *name,
+					 const xmlChar *URI);
+xsltTransformFunction
+	xsltExtModuleElementLookup	(const xmlChar *name,
+					 const xmlChar *URI);
+xsltPreComputeFunction
+	xsltExtModuleElementPreComputeLookup
+					(const xmlChar *name,
+					 const xmlChar *URI);
+int	xsltUnregisterExtModuleElement	(const xmlChar *name,
+					 const xmlChar *URI);
+
+/*
+ * top-level elements
+ */
+int	xsltRegisterExtModuleTopLevel	(const xmlChar *name,
+					 const xmlChar *URI,
+					 xsltPreComputeFunction function);
+xsltPreComputeFunction
+	xsltExtModuleTopLevelLookup	(const xmlChar *name,
+					 const xmlChar *URI);
+int	xsltUnregisterExtModuleTopLevel	(const xmlChar *name,
+					 const xmlChar *URI);
+
+
+/* These 2 functions are deprecated for use within modules */
 int		xsltRegisterExtFunction	(xsltTransformContextPtr ctxt,
 					 const xmlChar *name,
 					 const xmlChar *URI,
-					 xmlXPathEvalFunc function);
+					 xmlXPathFunction function);
 int		xsltRegisterExtElement	(xsltTransformContextPtr ctxt,
 					 const xmlChar *name,
 					 const xmlChar *URI,
@@ -84,6 +174,11 @@
 void		xsltFreeCtxtExts	(xsltTransformContextPtr ctxt);
 void		xsltFreeExts		(xsltStylesheetPtr style);
 
+
+/**
+ * Test module http://xmlsoft.org/XSLT/
+ */
+void	xsltRegisterTestModule		(void);
 
 #ifdef __cplusplus
 }
Index: libxslt/functions.c
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/functions.c,v
retrieving revision 1.34
diff -u -r1.34 functions.c
--- libxslt/functions.c	2001/07/23 00:55:43	1.34
+++ libxslt/functions.c	2001/07/25 14:54:36
@@ -51,6 +51,41 @@
  */
 #define DOCBOOK_XSL_HACK
 
+/**
+ * xsltXPathFunctionLookup:
+ * @ctxt:  a void * but the XSLT transformation context actually
+ * @name:  the function name
+ * @ns_uri:  the function namespace URI
+ *
+ * This is the entry point when a function is needed by the XPath
+ * interpretor.
+ *
+ * Returns the callback function or NULL if not found
+ */
+xmlXPathFunction
+xsltXPathFunctionLookup (void *ctxt ATTRIBUTE_UNUSED,
+			 const xmlChar *name, const xmlChar *ns_uri) {
+    xmlXPathFunction ret;
+
+    if ((name == NULL) || (ns_uri == NULL))
+	return (NULL);
+
+#ifdef WITH_XSLT_DEBUG_FUNCTION
+    xsltGenericDebug(xsltGenericDebugContext,
+            "Lookup function {%s}%s\n", ns_uri, name);
+#endif
+
+    ret = xsltExtModuleFunctionLookup(name, ns_uri);
+
+#ifdef WITH_XSLT_DEBUG_FUNCTION
+    if (ret != NULL)
+        xsltGenericDebug(xsltGenericDebugContext,
+            "found function %s\n", name);
+#endif
+    return(ret);
+}
+
+
 /************************************************************************
  *									*
  *			Module interfaces				*
@@ -625,7 +660,11 @@
 
     name = xmlSplitQName2(obj->stringval, &prefix);
     if (name == NULL) {
+	xmlNsPtr ns;
+
 	name = xmlStrdup(obj->stringval);
+	ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL);
+	nsURI = xmlStrdup(ns->href);
     } else {
 	nsURI = xmlXPathNsLookup(ctxt->context, prefix);
 	if (nsURI == NULL) {
@@ -636,7 +675,7 @@
 	}
     }
 
-    if (xmlHashLookup2(tctxt->extElements, name, nsURI) != NULL) {
+    if (xsltExtElementLookup(tctxt, name, nsURI) != NULL) {
 	valuePush(ctxt, xmlXPathNewBoolean(1));
     } else {
 	valuePush(ctxt, xmlXPathNewBoolean(0));
@@ -737,171 +776,6 @@
 
 /************************************************************************
  * 									*
- * 		Test of the extension module API			*
- * 									*
- ************************************************************************/
-
-static xmlChar *testData = NULL;
-
-/**
- * xsltExtFunctionTest:
- * @ctxt:  the XPath Parser context
- * @nargs:  the number of arguments
- *
- * function libxslt:test() for testing the extensions support.
- */
-static void
-xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, int nargs)
-{
-    xsltTransformContextPtr tctxt;
-    void *data;
-
-    if (testData == NULL) {
-	xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
-        xsltGenericError(xsltGenericErrorContext,
-                         "xsltExtFunctionTest: not initialized\n");
-        return;
-    }
-    tctxt = xsltXPathGetTransformContext(ctxt);
-    if (tctxt == NULL) {
-	xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
-        xsltGenericError(xsltGenericErrorContext,
-                         "xsltExtFunctionTest: failed to get the transformation context\n");
-        return;
-    }
-    data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
-    if (data == NULL) {
-	xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
-        xsltGenericError(xsltGenericErrorContext,
-                         "xsltExtFunctionTest: failed to get module data\n");
-        return;
-    }
-    if (data != testData) {
-	xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
-        xsltGenericError(xsltGenericErrorContext,
-                         "xsltExtFunctionTest: got wrong module data\n");
-        return;
-    }
-#ifdef WITH_XSLT_DEBUG_FUNCTION
-    xsltGenericDebug(xsltGenericDebugContext,
-                     "libxslt:test() called with %d args\n", nargs);
-#endif
-}
-
-/**
- * xsltExtElementTest:
- * @ctxt:  an XSLT processing context
- * @node:  The current node
- * @inst:  the instruction in the stylesheet
- * @comp:  precomputed informations
- *
- * Process a libxslt:test node
- */
-static void
-xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
-                   xmlNodePtr inst,
-                   xsltStylePreCompPtr comp ATTRIBUTE_UNUSED)
-{
-    xmlNodePtr comment;
-
-    if (testData == NULL) {
-	xsltPrintErrorContext(ctxt, NULL, inst);
-        xsltGenericError(xsltGenericErrorContext,
-                         "xsltExtElementTest: not initialized\n");
-        return;
-    }
-    if (ctxt == NULL) {
-	xsltPrintErrorContext(ctxt, NULL, inst);
-        xsltGenericError(xsltGenericErrorContext,
-                         "xsltExtElementTest: no transformation context\n");
-        return;
-    }
-    if (node == NULL) {
-	xsltPrintErrorContext(ctxt, NULL, inst);
-        xsltGenericError(xsltGenericErrorContext,
-                         "xsltExtElementTest: no current node\n");
-        return;
-    }
-    if (inst == NULL) {
-	xsltPrintErrorContext(ctxt, NULL, inst);
-        xsltGenericError(xsltGenericErrorContext,
-                         "xsltExtElementTest: no instruction\n");
-        return;
-    }
-    if (ctxt->insert == NULL) {
-	xsltPrintErrorContext(ctxt, NULL, inst);
-        xsltGenericError(xsltGenericErrorContext,
-                         "xsltExtElementTest: no insertion point\n");
-        return;
-    }
-    comment =
-        xmlNewComment((const xmlChar *)
-                      "libxslt:test element test worked");
-    xmlAddChild(ctxt->insert, comment);
-}
-
-/**
- * xsltExtInitTest:
- * @ctxt:  an XSLT transformation context
- * @URI:  the namespace URI for the extension
- *
- * A function called at initialization time of an XSLT extension module
- *
- * Returns a pointer to the module specific data for this transformation
- */
-static void *
-xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI)
-{
-    if (testData != NULL) {
-	xsltPrintErrorContext(ctxt, NULL, NULL);
-        xsltGenericError(xsltGenericErrorContext,
-                         "xsltExtInitTest: already initialized\n");
-        return (NULL);
-    }
-    testData = (void *) "test data";
-    xsltRegisterExtFunction(ctxt, (const xmlChar *) "test",
-                            (const xmlChar *) XSLT_DEFAULT_URL,
-                            xsltExtFunctionTest);
-    xsltRegisterExtElement(ctxt, (const xmlChar *) "test",
-                            (const xmlChar *) XSLT_DEFAULT_URL,
-                            xsltExtElementTest);
-
-    xsltGenericDebug(xsltGenericDebugContext,
-                     "Registered test module : %s\n", URI);
-    return (testData);
-}
-
-
-/**
- * xsltExtShutdownTest:
- * @ctxt:  an XSLT transformation context
- * @URI:  the namespace URI for the extension
- * @data:  the data associated to this module
- *
- * A function called at shutdown time of an XSLT extension module
- */
-static void
-xsltExtShutdownTest(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED,
-                    const xmlChar * URI, void *data)
-{
-    if (testData == NULL) {
-	xsltPrintErrorContext(ctxt, NULL, NULL);
-        xsltGenericError(xsltGenericErrorContext,
-                         "xsltExtShutdownTest: not initialized\n");
-        return;
-    }
-    if (data != testData) {
-	xsltPrintErrorContext(ctxt, NULL, NULL);
-        xsltGenericError(xsltGenericErrorContext,
-                         "xsltExtShutdownTest: wrong data\n");
-    }
-    testData = NULL;
-    xsltGenericDebug(xsltGenericDebugContext,
-                     "Unregistered test module : %s\n", URI);
-}
-
-/************************************************************************
- * 									*
  * 		Registration of XSLT and libxslt functions		*
  * 									*
  ************************************************************************/
@@ -932,8 +806,4 @@
                          xsltElementAvailableFunction);
     xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available",
                          xsltFunctionAvailableFunction);
-
-    xsltRegisterExtModule((const xmlChar *) XSLT_DEFAULT_URL,
-	                  xsltExtInitTest,
-                          xsltExtShutdownTest);
 }
Index: libxslt/functions.h
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/functions.h,v
retrieving revision 1.5
diff -u -r1.5 functions.h
--- libxslt/functions.h	2001/06/28 14:23:39	1.5
+++ libxslt/functions.h	2001/07/25 14:54:36
@@ -18,6 +18,19 @@
 extern "C" {
 #endif
 
+/**
+ * XSLT_REGISTER_FUNCTION_LOOKUP:
+ *
+ * registering macro, not general purpose at all but used in different modules
+ */
+#define XSLT_REGISTER_FUNCTION_LOOKUP(ctxt)			\
+    xmlXPathRegisterFuncLookup((ctxt)->xpathCtxt,		\
+		xsltXPathFunctionLookup, (void *)(ctxt));
+
+xmlXPathFunction
+	xsltXPathFunctionLookup	(void *ctxt, const xmlChar *name,
+				 const xmlChar *ns_uri);
+
 /*
  * Interfaces for the functions implementations
  */
Index: libxslt/preproc.c
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/preproc.c,v
retrieving revision 1.26
diff -u -r1.26 preproc.c
--- libxslt/preproc.c	2001/07/14 20:01:17	1.26
+++ libxslt/preproc.c	2001/07/25 14:54:36
@@ -36,6 +36,7 @@
 #include "preproc.h"
 #include "extra.h"
 #include "imports.h"
+#include "extensions.h"
 
 #ifdef WITH_XSLT_DEBUG
 #define WITH_XSLT_DEBUG_PREPROC
@@ -1343,6 +1344,15 @@
 	if (IS_XSLT_NAME(inst, "document")) {
 	    xsltDocumentComp(style, inst);
 	} else {
+	    xsltPreComputeFunction function;
+	    /*
+	     * Precompute the element
+	     */
+	    function =
+		xsltExtModuleElementPreComputeLookup(inst->name,
+						     inst->ns->href);
+	    if (function != NULL)
+		function(style, inst);
 	    /*
 	     * Mark the element for later recognition.
 	     */
Index: libxslt/transform.c
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/transform.c,v
retrieving revision 1.129
diff -u -r1.129 transform.c
--- libxslt/transform.c	2001/07/12 01:32:04	1.129
+++ libxslt/transform.c	2001/07/25 14:54:37
@@ -232,6 +232,7 @@
     cur->xpathCtxt->proximityPosition = 0;
     cur->xpathCtxt->contextSize = 0;
     XSLT_REGISTER_VARIABLE_LOOKUP(cur);
+    XSLT_REGISTER_FUNCTION_LOOKUP(cur);
     cur->xpathCtxt->nsHash = style->nsHash;
     docu = xsltNewDocument(cur, doc);
     if (docu == NULL) {
@@ -631,7 +632,7 @@
  ************************************************************************/
 
 void xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
-	                xsltStackElemPtr params);
+			xsltStackElemPtr params);
 /**
  * xsltDefaultProcessOneNode:
  * @ctxt:  a XSLT process context
@@ -1128,8 +1129,7 @@
              * Flagged as an extension element
              */
             function = (xsltTransformFunction)
-                xmlHashLookup2(ctxt->extElements, cur->name,
-                               cur->ns->href);
+                xsltExtElementLookup(ctxt, cur->name, cur->ns->href);
             if (function == NULL) {
                 xmlNodePtr child;
                 int found = 0;
Index: libxslt/transform.h
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/transform.h,v
retrieving revision 1.15
diff -u -r1.15 transform.h
--- libxslt/transform.h	2001/07/08 20:21:05	1.15
+++ libxslt/transform.h	2001/07/25 14:54:37
@@ -26,6 +26,11 @@
 /**
  * Private Interfaces
  */
+xsltTransformFunction
+		xsltExtElementLookup	(xsltTransformContextPtr ctxt,
+					 const xmlChar *name,
+					 const xmlChar *URI);
+
 xmlDocPtr	xsltApplyStylesheet	(xsltStylesheetPtr style,
 					 xmlDocPtr doc,
 					 const char **params);
Index: libxslt/variables.c
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/variables.c,v
retrieving revision 1.46
diff -u -r1.46 variables.c
--- libxslt/variables.c	2001/07/12 01:32:04	1.46
+++ libxslt/variables.c	2001/07/25 14:54:38
@@ -358,7 +358,7 @@
 	    xmlNodePtr oldInsert;
 
 	    container = xmlNewDocNode(ctxt->output, NULL,
-		                      (const xmlChar *) "fake", NULL);
+				      (const xmlChar *) "fake", NULL);
 	    if (container == NULL)
 		return(NULL);
 
@@ -472,7 +472,7 @@
 	    xmlNodePtr oldInsert;
 
 	    container = xmlNewDocNode(ctxt->output, NULL,
-		                      (const xmlChar *) "fake", NULL);
+				      (const xmlChar *) "fake", NULL);
 	    if (container == NULL)
 		return(NULL);
 
Index: libxslt/xslt.c
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/xslt.c,v
retrieving revision 1.62
diff -u -r1.62 xslt.c
--- libxslt/xslt.c	2001/07/12 01:32:04	1.62
+++ libxslt/xslt.c	2001/07/25 14:54:39
@@ -328,6 +328,7 @@
     cur->exclPrefixNr = 0;
     cur->exclPrefixMax = 0;
     cur->exclPrefixTab = NULL;
+    cur->extInfos = NULL;
     return(cur);
 }
 
@@ -369,6 +370,7 @@
     xsltFreeNamespaceAliasHashes(sheet);
     xsltFreeStyleDocuments(sheet);
     xsltFreeStylePreComps(sheet);
+    xsltShutdownExts(sheet);
     if (sheet->doc != NULL)
         xmlFreeDoc(sheet->doc);
     if (sheet->variables != NULL)
@@ -1247,24 +1249,21 @@
 /**
  * xsltParseTemplateContent:
  * @style:  the XSLT stylesheet
- * @ret:  the "template" structure
  * @template:  the container node (can be a document for literal results)
  *
- * parse an XSLT template element content
+ * parse a template content-model
  * Clean-up the template content from unwanted ignorable blank nodes
  * and process xslt:text
  */
 
-static void
-xsltParseTemplateContent(xsltStylesheetPtr style, xsltTemplatePtr ret,
-	                 xmlNodePtr template) {
+void
+xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr template) {
     xmlNodePtr cur, delete;
     /*
      * This content comes from the stylesheet
      * For stylesheets, the set of whitespace-preserving
      * element names consists of just xsl:text.
      */
-    ret->elem = template;
     cur = template->children;
     delete = NULL;
     while (cur != NULL) {
@@ -1412,8 +1411,6 @@
 	    break;
 	cur = cur->next;
     }
-
-    ret->content = template->children;
 }
 
 /**
@@ -1599,7 +1596,9 @@
     /*
      * parse the content and register the pattern
      */
-    xsltParseTemplateContent(style, ret, template);
+    xsltParseTemplateContent(style, template);
+    ret->elem = template;
+    ret->content = template->children;
     xsltAddTemplate(style, ret, mode, modeURI);
 
 error:
@@ -1652,28 +1651,44 @@
 
     cur = top->children;
 
+    /*
+     * process xsl:import elements
+     */
     while (cur != NULL) {
 	if (IS_BLANK_NODE(cur)) {
             cur = cur->next;
 	    continue;
-	}
-	if (!(IS_XSLT_ELEM(cur))) {
-#ifdef WITH_XSLT_DEBUG_PARSING
-	    xsltGenericDebug(xsltGenericDebugContext,
-		    "xsltParseStylesheetTop : found foreign element %s\n",
-		    cur->name);
-#endif
-            cur = cur->next;
-	    continue;
 	}
-	if (IS_XSLT_NAME(cur, "import")) {
+	if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
 	    xsltParseStylesheetImport(style, cur);
 	} else
 	    break;
 	cur = cur->next;
     }
+    /*
+     * process other top-level elements
+     */
     while (cur != NULL) {
+	if (IS_BLANK_NODE(cur)) {
+	    cur = cur->next;
+	    continue;
+	}
+	if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
+	    xsltGenericError(xsltGenericErrorContext,
+		     "Found a top-level element %s with null namespace URI\n",
+		     cur->name);
+	    style->errors++;
+	    cur = cur->next;
+	    continue;
+	}
 	if (!(IS_XSLT_ELEM(cur))) {
+	    xsltPreComputeFunction function;
+
+	    function = xsltExtModuleTopLevelLookup(cur->name,
+						   cur->ns->href);
+	    if (function != NULL)
+		function(style, cur);
+
 #ifdef WITH_XSLT_DEBUG_PARSING
 	    xsltGenericDebug(xsltGenericDebugContext,
 		    "xsltParseStylesheetTop : found foreign element %s\n",
@@ -1819,7 +1834,9 @@
 	/*
 	 * parse the content and register the pattern
 	 */
-	xsltParseTemplateContent(ret, template, (xmlNodePtr) doc);
+	xsltParseTemplateContent(ret, (xmlNodePtr) doc);
+	template->elem = (xmlNodePtr) doc;
+	template->content = doc->children;
 	xsltAddTemplate(ret, template, NULL, NULL);
     }
 
Index: libxslt/xsltInternals.h
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/xsltInternals.h,v
retrieving revision 1.57
diff -u -r1.57 xsltInternals.h
--- libxslt/xsltInternals.h	2001/07/23 00:55:43	1.57
+++ libxslt/xsltInternals.h	2001/07/25 14:54:39
@@ -323,6 +323,11 @@
     int       exclPrefixMax;	/* size of the array */
 
     void     *_private;		/* user defined data */
+
+    /*
+     * Extensions
+     */
+    xmlHashTablePtr extInfos;	/* the extension data */
 };
 
 /*
Index: libxslt/xsltutils.c
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/xsltutils.c,v
retrieving revision 1.44
diff -u -r1.44 xsltutils.c
--- libxslt/xsltutils.c	2001/07/23 00:55:43	1.44
+++ libxslt/xsltutils.c	2001/07/25 14:54:40
@@ -288,7 +288,7 @@
     const xmlChar *name = NULL;
     const char *type = "error";
 
-    if ((node != NULL) && (ctxt != NULL))
+    if ((node == NULL) && (ctxt != NULL))
 	node = ctxt->inst;
 
     if (node != NULL)  {
Index: xsltproc/xsltproc.c
===================================================================
RCS file: /cvs/gnome/libxslt/xsltproc/xsltproc.c,v
retrieving revision 1.3
diff -u -r1.3 xsltproc.c
--- xsltproc/xsltproc.c	2001/07/23 21:47:41	1.3
+++ xsltproc/xsltproc.c	2001/07/25 14:54:40
@@ -406,9 +406,10 @@
     xmlSubstituteEntitiesDefault(1);
 
     /*
-     * Register the EXSLT extensions
+     * Register the EXSLT extensions and the test module
      */
     exsltRegisterAll();
+    xsltRegisterTestModule();
 
     for (i = 1; i < argc; i++) {
         if ((!strcmp(argv[i], "-maxdepth")) ||


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