1 <?xml version="1.0" encoding="ISO-8859-1"?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /><style type="text/css">
4 TD {font-family: Verdana,Arial,Helvetica}
5 BODY {font-family: Verdana,Arial,Helvetica; margin-top: 2em; margin-left: 0em; margin-right: 0em}
6 H1 {font-family: Verdana,Arial,Helvetica}
7 H2 {font-family: Verdana,Arial,Helvetica}
8 H3 {font-family: Verdana,Arial,Helvetica}
9 A:link, A:visited, A:active { text-decoration: underline }
10 </style><title>Writing extensions</title></head><body bgcolor="#8b7765" text="#000000" link="#a06060" vlink="#000000"><table border="0" width="100%" cellpadding="5" cellspacing="0" align="center"><tr><td width="120"><a href="http://swpat.ffii.org/"><img src="epatents.png" alt="Action against software patents" /></a></td><td width="180"><a href="http://www.gnome.org/"><img src="gnome2.png" alt="GNOME2 Logo" /></a><a href="http://www.w3.org/Status"><img src="w3c.png" alt="W3C logo" /></a><a href="http://www.redhat.com"><img src="redhat.gif" alt="Red Hat Logo" /></a><div align="left"><a href="http://xmlsoft.org/XSLT/"><img src="Libxslt-Logo-180x168.gif" alt="Made with Libxslt Logo" /></a></div></td><td><table border="0" width="90%" cellpadding="2" cellspacing="0" align="center" bgcolor="#000000"><tr><td><table width="100%" border="0" cellspacing="1" cellpadding="3" bgcolor="#fffacd"><tr><td align="center"><h1>The XSLT C library for GNOME</h1><h2>Writing extensions</h2></td></tr></table></td></tr></table></td></tr></table><table border="0" cellpadding="4" cellspacing="0" width="100%" align="center"><tr><td bgcolor="#8b7765"><table border="0" cellspacing="0" cellpadding="2" width="100%"><tr><td valign="top" width="200" bgcolor="#8b7765"><table border="0" cellspacing="0" cellpadding="1" width="100%" bgcolor="#000000"><tr><td><table width="100%" border="0" cellspacing="1" cellpadding="3"><tr><td colspan="1" bgcolor="#eecfa1" align="center"><center><b>Main Menu</b></center></td></tr><tr><td bgcolor="#fffacd"><form action="search.php" enctype="application/x-www-form-urlencoded" method="get"><input name="query" type="text" size="20" value="" /><input name="submit" type="submit" value="Search ..." /></form><ul><li><a href="index.html">Home</a></li><li><a href="intro.html">Introduction</a></li><li><a href="docs.html">Documentation</a></li><li><a href="bugs.html">Reporting bugs and getting help</a></li><li><a href="help.html">How to help</a></li><li><a href="downloads.html">Downloads</a></li><li><a href="FAQ.html">FAQ</a></li><li><a href="news.html">News</a></li><li><a href="xsltproc2.html">The xsltproc tool</a></li><li><a href="docbook.html">DocBook</a></li><li><a href="API.html">The programming API</a></li><li><a href="python.html">Python and bindings</a></li><li><a href="internals.html">Library internals</a></li><li><a href="extensions.html">Writing extensions</a></li><li><a href="contribs.html">Contributions</a></li><li><a href="EXSLT/index.html" style="font-weight:bold">libexslt</a></li><li><a href="xslt.html">flat page</a>, <a href="site.xsl">stylesheet</a></li><li><a href="html/index.html" style="font-weight:bold">API Menu</a></li><li><a href="ChangeLog.html">ChangeLog</a></li></ul></td></tr></table><table width="100%" border="0" cellspacing="1" cellpadding="3"><tr><td colspan="1" bgcolor="#eecfa1" align="center"><center><b>Related links</b></center></td></tr><tr><td bgcolor="#fffacd"><ul><li><a href="tutorial/libxslttutorial.html">Tutorial</a>,
11 <a href="tutorial2/libxslt_pipes.html">Tutorial2</a></li><li><a href="xsltproc.html">Man page for xsltproc</a></li><li><a href="http://mail.gnome.org/archives/xslt/">Mail archive</a></li><li><a href="http://xmlsoft.org/">XML libxml2</a></li><li><a href="ftp://xmlsoft.org/">FTP</a></li><li><a href="http://www.zlatkovic.com/projects/libxml/">Windows binaries</a></li><li><a href="http://garypennington.net/libxml2/">Solaris binaries</a></li><li><a href="http://www.explain.com.au/oss/libxml2xslt.html">MacOsX binaries</a></li><li><a href="http://bugzilla.gnome.org/buglist.cgi?product=libxslt">Bug Tracker</a></li><li><a href="http://codespeak.net/lxml/">lxml Python bindings</a></li><li><a href="http://cpan.uwinnipeg.ca/dist/XML-LibXSLT">Perl XSLT bindings</a></li><li><a href="http://www.zend.com/php5/articles/php5-xmlphp.php#Heading17">XSLT with PHP</a></li><li><a href="http://www.mod-xslt2.com/">Apache module</a></li><li><a href="http://sourceforge.net/projects/libxml2-pas/">Pascal bindings</a></li><li><a href="http://xsldbg.sourceforge.net/">Xsldbg Debugger</a></li></ul></td></tr></table><table width="100%" border="0" cellspacing="1" cellpadding="3"><tr><td colspan="1" bgcolor="#eecfa1" align="center"><center><b>API Indexes</b></center></td></tr><tr><td bgcolor="#fffacd"><ul><li><a href="APIchunk0.html">Alphabetic</a></li><li><a href="APIconstructors.html">Constructors</a></li><li><a href="APIfunctions.html">Functions/Types</a></li><li><a href="APIfiles.html">Modules</a></li><li><a href="APIsymbols.html">Symbols</a></li></ul></td></tr></table></td></tr></table></td><td valign="top" bgcolor="#8b7765"><table border="0" cellspacing="0" cellpadding="1" width="100%"><tr><td><table border="0" cellspacing="0" cellpadding="1" width="100%" bgcolor="#000000"><tr><td><table border="0" cellpadding="3" cellspacing="1" width="100%"><tr><td bgcolor="#fffacd"><h3>Table of content</h3><ul><li><a href="extensions.html#Introducti">Introduction</a></li>
12 <li><a href="extensions.html#Basics">Basics</a></li>
13 <li><a href="extensions.html#Keep">Extension modules</a></li>
14 <li><a href="extensions.html#Registerin">Registering a module</a></li>
15 <li><a href="extensions.html#module">Loading a module</a></li>
16 <li><a href="extensions.html#Registerin1">Registering an extension
18 <li><a href="extensions.html#Implementi">Implementing an extension
20 <li><a href="extensions.html#Examples">Examples for extension
22 <li><a href="extensions.html#Registerin2">Registering an extension
24 <li><a href="extensions.html#Implementi1">Implementing an extension
26 <li><a href="extensions.html#Example">Example for extension
28 <li><a href="extensions.html#shutdown">The shutdown of a module</a></li>
29 <li><a href="extensions.html#Future">Future work</a></li>
30 </ul><h3><a name="Introducti1" id="Introducti1">Introduction</a></h3><p>This document describes the work needed to write extensions to the
31 standard XSLT library for use with <a href="http://xmlsoft.org/XSLT/">libxslt</a>, the <a href="http://www.w3.org/TR/xslt">XSLT</a> C library developed for the <a href="http://www.gnome.org/">GNOME</a> project.</p><p>Before starting reading this document it is highly recommended to get
32 familiar with <a href="internals.html">the libxslt internals</a>.</p><p>Note: this documentation is by definition incomplete and I am not good at
33 spelling, grammar, so patches and suggestions are <a href="mailto:veillard@redhat.com">really welcome</a>.</p><h3><a name="Basics" id="Basics">Basics</a></h3><p>The <a href="http://www.w3.org/TR/xslt">XSLT specification</a> provides
34 two <a href="http://www.w3.org/TR/xslt">ways to extend an XSLT engine</a>:</p><ul><li>providing <a href="http://www.w3.org/TR/xslt">new extension
35 functions</a> which can be called from XPath expressions</li>
36 <li>providing <a href="http://www.w3.org/TR/xslt">new extension
37 elements</a> which can be inserted in stylesheets</li>
38 </ul><p>In both cases the extensions need to be associated to a new namespace,
39 i.e. an URI used as the name for the extension's namespace (there is no need
40 to have a resource there for this to work).</p><p>libxslt provides a few extensions itself, either in the libxslt namespace
41 "http://xmlsoft.org/XSLT/namespace" or in namespaces for other well known
42 extensions provided by other XSLT processors like Saxon, Xalan or XT.</p><h3><a name="Keep" id="Keep">Extension modules</a></h3><p>Since extensions are bound to a namespace name, usually sets of extensions
43 coming from a given source are using the same namespace name defining in
44 practice a group of extensions providing elements, functions or both. From
45 the libxslt point of view those are considered as an "extension module", and
46 most of the APIs work at a module point of view.</p><p>Registration of new functions or elements are bound to the activation of
47 the module. This is currently done by declaring the namespace as an extension
48 by using the attribute <code>extension-element-prefixes</code> on the
49 <code><a href="http://www.w3.org/TR/xslt">xsl:stylesheet</a></code>
50 element.</p><p>An extension module is defined by 3 objects:</p><ul><li>the namespace name associated</li>
51 <li>an initialization function</li>
52 <li>a shutdown function</li>
53 </ul><h3><a name="Registerin" id="Registerin">Registering a module</a></h3><p>Currently a libxslt module has to be compiled within the application using
54 libxslt. There is no code to load dynamically shared libraries associated to
55 a namespace (this may be added but is likely to become a portability
56 nightmare).</p><p>The current way to register a module is to link the code implementing it
57 with the application and to call a registration function:</p><pre>int xsltRegisterExtModule(const xmlChar *URI,
58 xsltExtInitFunction initFunc,
59 xsltExtShutdownFunction shutdownFunc);</pre><p>The associated header is read by:</p><pre>#include<libxslt/extensions.h></pre><p>which also defines the type for the initialization and shutdown
60 functions</p><h3><a name="module" id="module">Loading a module</a></h3><p>Once the module URI has been registered and if the XSLT processor detects
61 that a given stylesheet needs the functionalities of an extended module, this
62 one is initialized.</p><p>The xsltExtInitFunction type defines the interface for an initialization
64 * xsltExtInitFunction:
65 * @ctxt: an XSLT transformation context
66 * @URI: the namespace URI for the extension
68 * A function called at initialization time of an XSLT
71 * Returns a pointer to the module specific data for this
74 typedef void *(*xsltExtInitFunction)(xsltTransformContextPtr ctxt,
75 const xmlChar *URI);</pre><p>There are 3 things to notice:</p><ul><li>The function gets passed the namespace name URI as an argument. This
76 allows a single function to provide the initialization for multiple
78 <li>It also gets passed a transformation context. The initialization is
79 done at run time before any processing occurs on the stylesheet but it
80 will be invoked separately each time for each transformation.</li>
81 <li>It returns a pointer. This can be used to store module specific
82 information which can be retrieved later when a function or an element
83 from the extension is used. An obvious example is a connection to a
84 database which should be kept and reused along with the transformation.
85 NULL is a perfectly valid return; there is no way to indicate a failure
87 </ul><p>What this function is expected to do is:</p><ul><li>prepare the context for this module (like opening the database
89 <li>register the extensions specific to this module</li>
90 </ul><h3><a name="Registerin1" id="Registerin1">Registering an extension function</a></h3><p>There is a single call to do this registration:</p><pre>int xsltRegisterExtFunction(xsltTransformContextPtr ctxt,
93 xmlXPathEvalFunc function);</pre><p>The registration is bound to a single transformation instance referred by
94 ctxt, name is the UTF8 encoded name for the NCName of the function, and URI
95 is the namespace name for the extension (no checking is done, a module could
96 register functions or elements from a different namespace, but it is not
97 recommended).</p><h3><a name="Implementi" id="Implementi">Implementing an extension function</a></h3><p>The implementation of the function must have the signature of a libxml
98 XPath function:</p><pre>/**
100 * @ctxt: an XPath parser context
101 * @nargs: the number of arguments passed to the function
103 * an XPath evaluation function, the parameters are on the
104 * XPath context stack
107 typedef void (*xmlXPathEvalFunc)(xmlXPathParserContextPtr ctxt,
108 int nargs);</pre><p>The context passed to an XPath function is not an XSLT context but an <a href="internals.html#XPath1">XPath context</a>. However it is possible to
109 find one from the other:</p><ul><li>The function xsltXPathGetTransformContext provides this lookup facility:
110 <pre>xsltTransformContextPtr
111 xsltXPathGetTransformContext
112 (xmlXPathParserContextPtr ctxt);</pre>
114 <li>The <code>xmlXPathContextPtr</code> associated to an
115 <code>xsltTransformContext</code> is stored in the <code>xpathCtxt</code>
117 </ul><p>The first thing an extension function may want to do is to check the
118 arguments passed on the stack, the <code>nargs</code> parameter will tell how
119 many of them were provided on the XPath expression. The macro valuePop will
120 extract them from the XPath stack:</p><pre>#include <libxml/xpath.h>
121 #include <libxml/xpathInternals.h>
123 xmlXPathObjectPtr obj = valuePop(ctxt); </pre><p>Note that <code>ctxt</code> is the XPath context not the XSLT one. It is
124 then possible to examine the content of the value. Check <a href="internals.html#Descriptio">the description of XPath objects</a> if
125 necessary. The following is a common sequence checking whether the argument
126 passed is a string and converting it using the built-in XPath
127 <code>string()</code> function if this is not the case:</p><pre>if (obj->type != XPATH_STRING) {
128 valuePush(ctxt, obj);
129 xmlXPathStringFunction(ctxt, 1);
130 obj = valuePop(ctxt);
131 }</pre><p>Most common XPath functions are available directly at the C level and are
132 exported either in <code><libxml/xpath.h></code> or in
133 <code><libxml/xpathInternals.h></code>.</p><p>The extension function may also need to retrieve the data associated to
134 this module instance (the database connection in the previous example) this
135 can be done using the xsltGetExtData:</p><pre>void * xsltGetExtData(xsltTransformContextPtr ctxt,
136 const xmlChar *URI);</pre><p>Again the URI to be provided is the one which was used when registering
137 the module.</p><p>Once the function finishes, don't forget to:</p><ul><li>push the return value on the stack using <code>valuePush(ctxt,
139 <li>deallocate the parameters passed to the function using
140 <code>xmlXPathFreeObject(obj)</code></li>
141 </ul><h3><a name="Examples" id="Examples">Examples for extension functions</a></h3><p>The module libxslt/functions.c contains the sources of the XSLT built-in
142 functions, including document(), key(), generate-id(), etc. as well as a full
143 example module at the end. Here is the test function implementation for the
144 libxslt:test function:</p><pre>/**
145 * xsltExtFunctionTest:
146 * @ctxt: the XPath Parser context
147 * @nargs: the number of arguments
149 * function libxslt:test() for testing the extensions support.
152 xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, int nargs)
154 xsltTransformContextPtr tctxt;
157 tctxt = xsltXPathGetTransformContext(ctxt);
159 xsltGenericError(xsltGenericErrorContext,
160 "xsltExtFunctionTest: failed to get the transformation context\n");
163 data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
165 xsltGenericError(xsltGenericErrorContext,
166 "xsltExtFunctionTest: failed to get module data\n");
169 #ifdef WITH_XSLT_DEBUG_FUNCTION
170 xsltGenericDebug(xsltGenericDebugContext,
171 "libxslt:test() called with %d args\n", nargs);
173 }</pre><h3><a name="Registerin2" id="Registerin2">Registering an extension element</a></h3><p>There is a single call to do this registration:</p><pre>int xsltRegisterExtElement(xsltTransformContextPtr ctxt,
176 xsltTransformFunction function);</pre><p>It is similar to the mechanism used to register an extension function,
177 except that the signature of an extension element implementation is
178 different.</p><p>The registration is bound to a single transformation instance referred to
179 by ctxt, name is the UTF8 encoded name for the NCName of the element, and URI
180 is the namespace name for the extension (no checking is done, a module could
181 register elements for a different namespace, but it is not recommended).</p><h3><a name="Implementi1" id="Implementi1">Implementing an extension element</a></h3><p>The implementation of the element must have the signature of an XSLT
182 transformation function:</p><pre>/**
183 * xsltTransformFunction:
184 * @ctxt: the XSLT transformation context
185 * @node: the input node
186 * @inst: the stylesheet node
187 * @comp: the compiled information from the stylesheet
189 * signature of the function associated to elements part of the
190 * stylesheet language like xsl:if or xsl:apply-templates.
192 typedef void (*xsltTransformFunction)
193 (xsltTransformContextPtr ctxt,
196 xsltStylePreCompPtr comp);</pre><p>The first argument is the XSLT transformation context. The second and
197 third arguments are xmlNodePtr i.e. internal memory <a href="internals.html#libxml">representation of XML nodes</a>. They are
198 respectively <code>node</code> from the the input document being transformed
199 by the stylesheet and <code>inst</code> the extension element in the
200 stylesheet. The last argument is <code>comp</code> a pointer to a precompiled
201 representation of <code>inst</code> but usually for an extension function
202 this value is <code>NULL</code> by default (it could be added and associated
203 to the instruction in <code>inst->_private</code>).</p><p>The same functions are available from a function implementing an extension
204 element as in an extension function, including
205 <code>xsltGetExtData()</code>.</p><p>The goal of an extension element being usually to enrich the generated
206 output, it is expected that they will grow the currently generated output
207 tree. This can be done by grabbing ctxt->insert which is the current
208 libxml node being generated (Note this can also be the intermediate value
209 tree being built for example to initialize a variable, the processing should
210 be similar). The functions for libxml tree manipulation from <a href="http://xmlsoft.org/html/libxml-tree.html"><libxml/tree.h></a> can
211 be employed to extend or modify the tree, but it is required to preserve the
212 insertion node and its ancestors since there are existing pointers to those
213 elements still in use in the XSLT template execution stack.</p><h3><a name="Example" id="Example">Example for extension elements</a></h3><p>The module libxslt/transform.c contains the sources of the XSLT built-in
214 elements, including xsl:element, xsl:attribute, xsl:if, etc. There is a small
215 but full example in functions.c providing the implementation for the
216 libxslt:test element, it will output a comment in the result tree:</p><pre>/**
217 * xsltExtElementTest:
218 * @ctxt: an XSLT processing context
219 * @node: The current node
220 * @inst: the instruction in the stylesheet
221 * @comp: precomputed information
223 * Process a libxslt:test node
226 xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
228 xsltStylePreCompPtr comp)
233 xsltGenericError(xsltGenericErrorContext,
234 "xsltExtElementTest: no transformation context\n");
238 xsltGenericError(xsltGenericErrorContext,
239 "xsltExtElementTest: no current node\n");
243 xsltGenericError(xsltGenericErrorContext,
244 "xsltExtElementTest: no instruction\n");
247 if (ctxt->insert == NULL) {
248 xsltGenericError(xsltGenericErrorContext,
249 "xsltExtElementTest: no insertion point\n");
253 xmlNewComment((const xmlChar *)
254 "libxslt:test element test worked");
255 xmlAddChild(ctxt->insert, comment);
256 }</pre><h3><a name="shutdown" id="shutdown">The shutdown of a module</a></h3><p>When the XSLT processor ends a transformation, the shutdown function (if
257 it exists) for each of the modules initialized is called. The
258 xsltExtShutdownFunction type defines the interface for a shutdown
259 function:</p><pre>/**
260 * xsltExtShutdownFunction:
261 * @ctxt: an XSLT transformation context
262 * @URI: the namespace URI for the extension
263 * @data: the data associated to this module
265 * A function called at shutdown time of an XSLT extension module
267 typedef void (*xsltExtShutdownFunction) (xsltTransformContextPtr ctxt,
269 void *data);</pre><p>This is really similar to a module initialization function except a third
270 argument is passed, it's the value that was returned by the initialization
271 function. This allows the routine to deallocate resources from the module for
272 example close the connection to the database to keep the same example.</p><h3><a name="Future" id="Future">Future work</a></h3><p>Well, some of the pieces missing:</p><ul><li>a way to load shared libraries to instantiate new modules</li>
273 <li>a better detection of extension functions usage and their registration
274 without having to use the extension prefix which ought to be reserved to
275 element extensions.</li>
276 <li>more examples</li>
277 <li>implementations of the <a href="http://www.exslt.org/">EXSLT</a> common
278 extension libraries, Thomas Broyer nearly finished implementing them.</li>
279 </ul><p></p><p><a href="bugs.html">Daniel Veillard</a></p></td></tr></table></td></tr></table></td></tr></table></td></tr></table></td></tr></table></body></html>