From bdffe03d8d210d8389839433b0f687715a05c555 Mon Sep 17 00:00:00 2001
From: Daniel Veillard Location: http://xmlsoft.org/XSLT/extensions.html Libxslt home page: http://xmlsoft.org/XSLT/ mailing-list archives: http://mail.gnome.org/archives/xslt/ Version: $Revision$ This document describes the work needed to write extensions to the standard
+XSLT library for use with libxslt, the
+XSLT C library developped for the Gnome project. Before starting reading this document it is highly recommended to get
+familiar with the libxslt internals. Note: this documentation is by definition incomplete and I am not good at
+spelling, grammar, so patches and suggestions are really welcome. The XSLT specification provides two
+ways to extend an XSLT engine: In both cases the extensions need to be associated to a new namespace, i.e.
+an URI used as the name for the extension's namespace (there is no need to
+have a resource there for this to work). libxslt provides a few extensions itself, either in libxslt namespace
+"http://xmlsoft.org/XSLT/" or in other namepsace for well known extensions
+provided by other XSLT processors like Saxon, Xalan or XT. Since extensions are bound to a namespace name, usually sets of extensions
+coming from a given source are using the same namespace name defining in
+practice a group of extensions providing elements, functions or both. From
+libxslt point of view those are considered as an "extension module", and most
+of the APIs work at a module point of view. Registration of new functions or elements are bound to the activation of
+the module, this is currently done by declaring the namespace as an extension
+by using the attribute And extension module is defined by 3 objects: Currently a libxslt module has to be compiled within the application using
+libxslt, there is no code to load dynamically shared libraries associated to
+namespace (this may be added but is likely to become a portability
+nightmare). So the current way to register a module is to link the code implementing it
+with the application and to call a registration function: The associated header is read by: which also defines the type for the initialization and shutdown
+functions Once the module URI has been registered and if the XSLT processor detects
+that a given stylesheet need the functionalities of an extended module, this
+one is initialized. The xsltExtInitFunction type defines the interface for an initialization
+function: There is 3 things to notice: What this function is expected to do is: There is a single call to do this registration: The registration is bound to a single transformation instance referred by
+ctxt, name is the UTF8 encoded name for the NCName of the function, and URI is
+the namespace name for the extension (no checking is done, a module could
+register functions or elements from a different namespace, but it is not
+recommended). The implementation of the function must have the signature of a libxml
+XPath function: The context passed to an XPath function is not an XSLT context but an XPath context. However it is possible to find
+one from the other: The first thing an extension function may want to do is to check the
+arguments passed on the stack, the Note that Most common XPath function are availbale directly at the C level and are
+exported either in The extension function may also need to retrieve the data associated to
+this module instance (the database connection in the previous example) this
+can be done using the xsltGetExtData: again the URI to be provided is the one used which was used when
+registering the module. Once the function finishes, don't forget to: The module libxslt/functions.c containsthe sources of the XSLT built-in
+functions, including document(), key(), generate-id(), etc. as well as a full
+example module at the end. Here is the test function implementation for the
+libxslt:test function: There is a single call to do this registration: It is similar to the mechanism used to register an extension function,
+except that the signature of an extension element implementation is different.
+ The registration is bound to a single transformation instance referred by
+ctxt, name is the UTF8 encoded name for the NCName of the element, and URI is
+the namespace name for the extension (no checking is done, a module could
+register elements for a different namespace, but it is not recommended). The implementation of the element must have the signature of an XSLT
+transformation function: The first argument is the XSLT transformation context. The second and third
+arguments are xmlNodePtr i.e. internal memory representation of XML nodes. They are
+respectively The same functions are available from a function implementing an extension
+element as in an extension function, including
+ The goal of extension element being usually to enrich the generated output,
+it is expected that they will grow the currently generated output tree, this
+can be done by grabbing ctxt->insert which is the current libxml node being
+generated (Note this can also be the intermediate value tree being built for
+example to initialize a variable, the processing should be similar). The
+functions for libxml tree manipulation from <libxml/tree.h> can
+be employed to extend or modify the tree, but it is required to preserve the
+insertion node and its ancestors since there is existing pointers to those
+elements still in use in the XSLT template execution stack. The module libxslt/transform.c containsthe sources of the XSLT built-in
+elements, including xsl:element, xsl:attribute, xsl:if, etc. There is a small
+but full example in functions.c providing the implementation for the
+libxslt:test element, it will output a comment in the result tree: Well some of the pieces missing: $Id$Writing extensions for XSLT C library for Gnome
+
+
+
+Table of content
+
+
+
+Introduction
+
+Basics
+
+
+
+
+Extension modules
+
+extension-element-prefixes
on the
+xsl:stylesheet
+element.
+
+
+Registering a module
+
+int xsltRegisterExtModule(const xmlChar *URI,
+ xsltExtInitFunction initFunc,
+ xsltExtShutdownFunction shutdownFunc);
+
+#include<libxslt/extensions.h>
+
+
+
+
+
+ Loading a module
+
+/**
+ * xsltExtInitFunction:
+ * @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
+ */
+typedef void *(*xsltExtInitFunction)(xsltTransformContextPtr ctxt,
+ const xmlChar *URI);
+
+
+
+
+
+
+
+Registering an extension function
+
+int xsltRegisterExtFunction(xsltTransformContextPtr ctxt,
+ const xmlChar *name,
+ const xmlChar *URI,
+ xmlXPathEvalFunc function);
+
+Implementing an extension function
+
+/**
+ * xmlXPathEvalFunc:
+ * @ctxt: an XPath parser context
+ * @nargs: the number of arguments passed to the function
+ *
+ * an XPath evaluation function, the parameters are on the
+ * XPath context stack
+ */
+
+typedef void (*xmlXPathEvalFunc)(xmlXPathParserContextPtr ctxt,
+ int nargs);
+
+
+
+
+xsltTransformContextPtr
+ xsltXPathGetTransformContext
+ (xmlXPathParserContextPtr ctxt);
+ xmlXPathContextPtr
associated to an
+ xsltTransformContext
is stored in the xpathCtxt
+ field.nargs
will precise how many of
+them were provided on the XPath expression. The macros valuePop will extract
+them from the XPath stack:#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+xmlXPathObjectPtr obj = valuePop(ctxt);
+
+ctxt
is the XPath context not the XSLT one. It is
+then possible to examine the content of the value. Check the description of XPath objects if
+necessary. The following is a common sequcnce checking whether the argument
+passed is a string and converting it using the built-in XPath
+string()
function if this is not the case:if (obj->type != XPATH_STRING) {
+ valuePush(ctxt, obj);
+ xmlXPathStringFunction(ctxt, 1);
+ obj = valuePop(ctxt);
+}
+
+<libxml/xpath.h>
or in
+<libxml/xpathInternals.h>
.void * xsltGetExtData(xsltTransformContextPtr ctxt,
+ const xmlChar *URI);
+
+
+
+
+valuePush(ctxt,
+ obj)
xmlXPathFreeObject(obj)
Examples for extension functions
+
+/**
+ * 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 (tctxt == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtFunctionTest: failed to get the transformation context\n");
+ return;
+ }
+ data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
+ if (data == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtFunctionTest: failed to get module data\n");
+ return;
+ }
+#ifdef WITH_XSLT_DEBUG_FUNCTION
+ xsltGenericDebug(xsltGenericDebugContext,
+ "libxslt:test() called with %d args\n", nargs);
+#endif
+}
+
+Registering an extension function
+
+int xsltRegisterExtElement(xsltTransformContextPtr ctxt,
+ const xmlChar *name,
+ const xmlChar *URI,
+ xsltTransformFunction function);
+
+Implementing an extension element
+
+/**
+ * xsltTransformFunction:
+ * @ctxt: the XSLT transformation context
+ * @node: the input node
+ * @inst: the stylesheet node
+ * @comp: the compiled information from the stylesheet
+ *
+ * signature of the function associated to elements part of the
+ * stylesheet language like xsl:if or xsl:apply-templates.
+ */
+typedef void (*xsltTransformFunction)
+ (xsltTransformContextPtr ctxt,
+ xmlNodePtr node,
+ xmlNodePtr inst,
+ xsltStylePreCompPtr comp);
+
+node
from the the input document being transformed
+by the stylesheet and inst
the extension element in the
+stylesheet. The last argument is comp
a pointer to a precompiled
+representation of inst
but usually for extension function this
+value is NULL
by default (it could be added and associated to the
+instruction in inst->_private
).xsltGetExtData()
.Example for extension elements
+
+/**
+ * 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)
+{
+ xmlNodePtr comment;
+
+ if (ctxt == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtElementTest: no transformation context\n");
+ return;
+ }
+ if (node == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtElementTest: no current node\n");
+ return;
+ }
+ if (inst == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtElementTest: no instruction\n");
+ return;
+ }
+ if (ctxt->insert == NULL) {
+ xsltGenericError(xsltGenericErrorContext,
+ "xsltExtElementTest: no insertion point\n");
+ return;
+ }
+ comment =
+ xmlNewComment((const xmlChar *)
+ "libxslt:test element test worked");
+ xmlAddChild(ctxt->insert, comment);
+}
+
+Future work
+
+
+
+
+
+
+
Location: http://xmlsoft.org/XSLT/internals.html
+ +Libxslt home page: http://xmlsoft.org/XSLT/
+ +mailing-list archives: http://mail.gnome.org/archives/xslt/
+ +Version: $Revision$
+ +The API for registrering those is Not Yet Completed, it is possible do do -though .... TODO
+There is a separate document explaining how the +extension support works.