source: trunk/third/libxslt/doc/extensions.html @ 21535

Revision 21535, 22.0 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21534, which included commits to RCS files with non-trunk default branches.
Line 
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">
4TD {font-family: Verdana,Arial,Helvetica}
5BODY {font-family: Verdana,Arial,Helvetica; margin-top: 2em; margin-left: 0em; margin-right: 0em}
6H1 {font-family: Verdana,Arial,Helvetica}
7H2 {font-family: Verdana,Arial,Helvetica}
8H3 {font-family: Verdana,Arial,Helvetica}
9A: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.zveno.com/open_source/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://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
17    function</a></li>
18  <li><a href="extensions.html#Implementi">Implementing an extension
19    function</a></li>
20  <li><a href="extensions.html#Examples">Examples for extension
21  functions</a></li>
22  <li><a href="extensions.html#Registerin2">Registering an extension
23    element</a></li>
24  <li><a href="extensions.html#Implementi1">Implementing an extension
25    element</a></li>
26  <li><a href="extensions.html#Example">Example for extension
27  elements</a></li>
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
31standard 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
32familiar with <a href="internals.html">the libxslt internals</a>.</p><p>Note: this documentation is by definition incomplete and I am not good at
33spelling, 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
34two <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,
39i.e. an URI used as the name for the extension's namespace (there is no need
40to 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
42extensions 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
43coming from a given source are using the same namespace name defining in
44practice a group of extensions providing elements, functions or both. From
45the libxslt point of view those are considered as an "extension module", and
46most of the APIs work at a module point of view.</p><p>Registration of new functions or elements are bound to the activation of
47the module. This is currently done by declaring the namespace as an extension
48by using the attribute  <code>extension-element-prefixes</code> on the
49<code><a href="http://www.w3.org/TR/xslt">xsl:stylesheet</a></code>
50element.</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
54libxslt. There is no code to load dynamically shared libraries associated to
55a namespace (this may be added but is likely to become a portability
56nightmare).</p><p>The current way to register a module is to link the code implementing it
57with 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&lt;libxslt/extensions.h&gt;</pre><p>which also defines the type for the initialization and shutdown
60functions</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
61that a given stylesheet needs the functionalities of an extended module, this
62one is initialized.</p><p>The xsltExtInitFunction type defines the interface for an initialization
63function:</p><pre>/**
64 * xsltExtInitFunction:
65 * @ctxt:  an XSLT transformation context
66 * @URI:  the namespace URI for the extension
67 *
68 * A function called at initialization time of an XSLT
69 * extension module
70 *
71 * Returns a pointer to the module specific data for this
72 * transformation
73 */
74typedef 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
77    logical modules.</li>
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
86    at this level</li>
87</ul><p>What this function is expected to do is:</p><ul><li>prepare the context for this module (like opening the database
88    connection)</li>
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,
91                            const xmlChar *name,
92                            const xmlChar *URI,
93                            xmlXPathEvalFunc function);</pre><p>The registration is bound to a single transformation instance referred by
94ctxt, name is the UTF8 encoded name for the NCName of the function, and URI
95is the namespace name for the extension (no checking is done, a module could
96register functions or elements from a different namespace, but it is not
97recommended).</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
98XPath function:</p><pre>/**
99 * xmlXPathEvalFunc:
100 * @ctxt: an XPath parser context
101 * @nargs: the number of arguments passed to the function
102 *
103 * an XPath evaluation function, the parameters are on the
104 * XPath context stack
105 */
106
107typedef 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
109find one from the other:</p><ul><li>The function xsltXPathGetTransformContext provides this lookup facility:
110    <pre>xsltTransformContextPtr
111         xsltXPathGetTransformContext
112                          (xmlXPathParserContextPtr ctxt);</pre>
113  </li>
114  <li>The <code>xmlXPathContextPtr</code> associated to an
115    <code>xsltTransformContext</code> is stored in the <code>xpathCtxt</code>
116    field.</li>
117</ul><p>The first thing an extension function may want to do is to check the
118arguments passed on the stack, the <code>nargs</code> parameter will tell how
119many of them were provided on the XPath expression. The macro valuePop will
120extract them from the XPath stack:</p><pre>#include &lt;libxml/xpath.h&gt;
121#include &lt;libxml/xpathInternals.h&gt;
122
123xmlXPathObjectPtr obj = valuePop(ctxt); </pre><p>Note that <code>ctxt</code> is the XPath context not the XSLT one. It is
124then possible to examine the content of the value. Check <a href="internals.html#Descriptio">the description of XPath objects</a> if
125necessary. The following is a common sequence checking whether the argument
126passed 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-&gt;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
132exported either in <code>&lt;libxml/xpath.h&gt;</code> or in
133<code>&lt;libxml/xpathInternals.h&gt;</code>.</p><p>The extension function may also need to retrieve the data associated to
134this module instance (the database connection in the previous example) this
135can 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
137the 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,
138    obj)</code></li>
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
142functions, including document(), key(), generate-id(), etc. as well as a full
143example module at the end. Here is the test function implementation for the
144libxslt:test function:</p><pre>/**
145 * xsltExtFunctionTest:
146 * @ctxt:  the XPath Parser context
147 * @nargs:  the number of arguments
148 *
149 * function libxslt:test() for testing the extensions support.
150 */
151static void
152xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, int nargs)
153{
154    xsltTransformContextPtr tctxt;
155    void *data;
156
157    tctxt = xsltXPathGetTransformContext(ctxt);
158    if (tctxt == NULL) {
159        xsltGenericError(xsltGenericErrorContext,
160            "xsltExtFunctionTest: failed to get the transformation context\n");
161        return;
162    }
163    data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL);
164    if (data == NULL) {
165        xsltGenericError(xsltGenericErrorContext,
166            "xsltExtFunctionTest: failed to get module data\n");
167        return;
168    }
169#ifdef WITH_XSLT_DEBUG_FUNCTION
170    xsltGenericDebug(xsltGenericDebugContext,
171                     "libxslt:test() called with %d args\n", nargs);
172#endif
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,
174                           const xmlChar *name,
175                           const xmlChar *URI,
176                           xsltTransformFunction function);</pre><p>It is similar to the mechanism used to register an extension function,
177except that the signature of an extension element implementation is
178different.</p><p>The registration is bound to a single transformation instance referred to
179by ctxt, name is the UTF8 encoded name for the NCName of the element, and URI
180is the namespace name for the extension (no checking is done, a module could
181register 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
182transformation 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
188 *
189 * signature of the function associated to elements part of the
190 * stylesheet language like xsl:if or xsl:apply-templates.
191 */
192typedef void (*xsltTransformFunction)
193                          (xsltTransformContextPtr ctxt,
194                           xmlNodePtr node,
195                           xmlNodePtr inst,
196                           xsltStylePreCompPtr comp);</pre><p>The first argument is the XSLT transformation context. The second and
197third arguments are xmlNodePtr i.e. internal memory <a href="internals.html#libxml">representation of  XML nodes</a>. They are
198respectively <code>node</code> from the the input document being transformed
199by the stylesheet and <code>inst</code> the extension element in the
200stylesheet. The last argument is <code>comp</code> a pointer to a precompiled
201representation of <code>inst</code> but usually for an extension function
202this value is <code>NULL</code> by default (it could be added and associated
203to the instruction in <code>inst-&gt;_private</code>).</p><p>The same functions are available from a function implementing an extension
204element as in an extension function, including
205<code>xsltGetExtData()</code>.</p><p>The goal of an extension element being usually to enrich the generated
206output, it is expected that they will grow the currently generated output
207tree. This can be done by grabbing ctxt-&gt;insert which is the current
208libxml node being generated (Note this can also be the intermediate value
209tree being built for example to initialize a variable, the processing should
210be similar). The functions for libxml tree manipulation from <a href="http://xmlsoft.org/html/libxml-tree.html">&lt;libxml/tree.h&gt;</a> can
211be employed to extend or modify the tree, but it is required to preserve the
212insertion node and its ancestors since there are existing pointers to those
213elements 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
214elements, including xsl:element, xsl:attribute, xsl:if, etc. There is a small
215but full example in functions.c providing the implementation for the
216libxslt: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 informations
222 *
223 * Process a libxslt:test node
224 */
225static void
226xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node,
227                   xmlNodePtr inst,
228                   xsltStylePreCompPtr comp)
229{
230    xmlNodePtr comment;
231
232    if (ctxt == NULL) {
233        xsltGenericError(xsltGenericErrorContext,
234                         "xsltExtElementTest: no transformation context\n");
235        return;
236    }
237    if (node == NULL) {
238        xsltGenericError(xsltGenericErrorContext,
239                         "xsltExtElementTest: no current node\n");
240        return;
241    }
242    if (inst == NULL) {
243        xsltGenericError(xsltGenericErrorContext,
244                         "xsltExtElementTest: no instruction\n");
245        return;
246    }
247    if (ctxt-&gt;insert == NULL) {
248        xsltGenericError(xsltGenericErrorContext,
249                         "xsltExtElementTest: no insertion point\n");
250        return;
251    }
252    comment =
253        xmlNewComment((const xmlChar *)
254                      "libxslt:test element test worked");
255    xmlAddChild(ctxt-&gt;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
257it exists) for each of the modules initialized is called.  The
258xsltExtShutdownFunction type defines the interface for a shutdown
259function:</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
264 *
265 * A function called at shutdown time of an XSLT extension module
266 */
267typedef void (*xsltExtShutdownFunction) (xsltTransformContextPtr ctxt,
268                                         const xmlChar *URI,
269                                         void *data);</pre><p>This is really similar to a module initialization function except a third
270argument is passed, it's the value that was returned by the initialization
271function. This allows the routine to deallocate resources from the module for
272example 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>
Note: See TracBrowser for help on using the repository browser.