diff options
Diffstat (limited to 'doc/extensions.html')
-rw-r--r-- | doc/extensions.html | 265 |
1 files changed, 133 insertions, 132 deletions
diff --git a/doc/extensions.html b/doc/extensions.html index aab2f428..ac06e7ff 100644 --- a/doc/extensions.html +++ b/doc/extensions.html @@ -13,54 +13,53 @@ A:link, A:visited, A:active { text-decoration: underline } <li><a href="extensions.html#Keep">Extension modules</a></li> <li><a href="extensions.html#Registerin">Registering a module</a></li> <li><a href="extensions.html#module">Loading a module</a></li> - <li><a href="extensions.html#Registerin1">Registering an extension - function</a></li> - <li><a href="extensions.html#Implementi">Implementing an extension - function</a></li> - <li><a href="extensions.html#Examples">Examples for extension - functions</a></li> - <li><a href="extensions.html#Registerin2">Registering an extension - element</a></li> - <li><a href="extensions.html#Implementi1">Implementing an extension - element</a></li> - <li><a href="extensions.html#Example">Example for extension - elements</a></li> + <li><a href="extensions.html#Registerin1">Registering an + extensionfunction</a></li> + <li><a href="extensions.html#Implementi">Implementing an + extensionfunction</a></li> + <li><a href="extensions.html#Examples">Examples for + extensionfunctions</a></li> + <li><a href="extensions.html#Registerin2">Registering an + extensionelement</a></li> + <li><a href="extensions.html#Implementi1">Implementing an + extensionelement</a></li> + <li><a href="extensions.html#Example">Example for extensionelements</a></li> <li><a href="extensions.html#shutdown">The shutdown of a module</a></li> <li><a href="extensions.html#Future">Future work</a></li> -</ul><h3><a name="Introducti1" id="Introducti1">Introduction</a></h3><p>This document describes the work needed to write extensions to the -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 -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 -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 -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 - functions</a> which can be called from XPath expressions</li> - <li>providing <a href="http://www.w3.org/TR/xslt">new extension - elements</a> which can be inserted in stylesheets</li> -</ul><p>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).</p><p>libxslt provides a few extensions itself, either in the libxslt namespace -"http://xmlsoft.org/XSLT/namespace" or in namespaces for other well known -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 -coming from a given source are using the same namespace name defining in -practice a group of extensions providing elements, functions or both. From -the libxslt point of view those are considered as an "extension module", and -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 -the module. This is currently done by declaring the namespace as an extension -by using the attribute <code>extension-element-prefixes</code> on the -<code><a href="http://www.w3.org/TR/xslt">xsl:stylesheet</a></code> -element.</p><p>An extension module is defined by 3 objects:</p><ul><li>the namespace name associated</li> +</ul><h3><a name="Introducti1" id="Introducti1">Introduction</a></h3><p>This document describes the work needed to write extensions to thestandard +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 +getfamiliar with <a href="internals.html">the libxslt internals</a>.</p><p>Note: this documentation is by definition incomplete and I am not good +atspelling, 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>providestwo +<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 + extensionfunctions</a>which can be called from XPath expressions</li> + <li>providing <a href="http://www.w3.org/TR/xslt">new + extensionelements</a>which can be inserted in stylesheets</li> +</ul><p>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 needto +have a resource there for this to work).</p><p>libxslt provides a few extensions itself, either in the libxslt +namespace"http://xmlsoft.org/XSLT/namespace" or in namespaces for other well +knownextensions 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 +extensionscoming from a given source are using the same namespace name +defining inpractice a group of extensions providing elements, functions or +both. Fromthe libxslt point of view those are considered as an "extension +module", andmost of the APIs work at a module point of view.</p><p>Registration of new functions or elements are bound to the activation +ofthe module. This is currently done by declaring the namespace as an +extensionby using the attribute <code>extension-element-prefixes</code>on +the<code><a href="http://www.w3.org/TR/xslt">xsl:stylesheet</a></code>element.</p><p>An extension module is defined by 3 objects:</p><ul><li>the namespace name associated</li> <li>an initialization function</li> <li>a shutdown function</li> -</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 -libxslt. There is no code to load dynamically shared libraries associated to -a namespace (this may be added but is likely to become a portability -nightmare).</p><p>The current way to register a module is to link the code implementing it -with the application and to call a registration function:</p><pre>int xsltRegisterExtModule(const xmlChar *URI, +</ul><h3><a name="Registerin" id="Registerin">Registering a module</a></h3><p>Currently a libxslt module has to be compiled within the application +usinglibxslt. There is no code to load dynamically shared libraries +associated toa namespace (this may be added but is likely to become a +portabilitynightmare).</p><p>The current way to register a module is to link the code implementing +itwith the application and to call a registration function:</p><pre>int xsltRegisterExtModule(const xmlChar *URI, xsltExtInitFunction initFunc, - 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 -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 -that a given stylesheet needs the functionalities of an extended module, this -one is initialized.</p><p>The xsltExtInitFunction type defines the interface for an initialization -function:</p><pre>/** + 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 +shutdownfunctions</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 +detectsthat a given stylesheet needs the functionalities of an extended +module, thisone is initialized.</p><p>The xsltExtInitFunction type defines the interface for an +initializationfunction:</p><pre>/** * xsltExtInitFunction: * @ctxt: an XSLT transformation context * @URI: the namespace URI for the extension @@ -72,30 +71,30 @@ function:</p><pre>/** * transformation */ typedef void *(*xsltExtInitFunction)(xsltTransformContextPtr ctxt, - 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 - allows a single function to provide the initialization for multiple - logical modules.</li> - <li>It also gets passed a transformation context. The initialization is - done at run time before any processing occurs on the stylesheet but it - will be invoked separately each time for each transformation.</li> - <li>It returns a pointer. This can be used to store module specific - information which can be retrieved later when a function or an element - from the extension is used. An obvious example is a connection to a - database which should be kept and reused along with the transformation. - NULL is a perfectly valid return; there is no way to indicate a failure - at this level</li> -</ul><p>What this function is expected to do is:</p><ul><li>prepare the context for this module (like opening the database - connection)</li> + 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. + Thisallows a single function to provide the initialization for + multiplelogical modules.</li> + <li>It also gets passed a transformation context. The initialization isdone + at run time before any processing occurs on the stylesheet but itwill be + invoked separately each time for each transformation.</li> + <li>It returns a pointer. This can be used to store module + specificinformation which can be retrieved later when a function or an + elementfrom the extension is used. An obvious example is a connection to + adatabase which should be kept and reused along with the + transformation.NULL is a perfectly valid return; there is no way to + indicate a failureat this level</li> +</ul><p>What this function is expected to do is:</p><ul><li>prepare the context for this module (like opening the + databaseconnection)</li> <li>register the extensions specific to this module</li> </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, const xmlChar *name, const xmlChar *URI, - xmlXPathEvalFunc function);</pre><p>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).</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 -XPath function:</p><pre>/** + xmlXPathEvalFunc function);</pre><p>The registration is bound to a single transformation instance referred +byctxt, name is the UTF8 encoded name for the NCName of the function, and +URIis the namespace name for the extension (no checking is done, a module +couldregister functions or elements from a different namespace, but it is +notrecommended).</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 +libxmlXPath function:</p><pre>/** * xmlXPathEvalFunc: * @ctxt: an XPath parser context * @nargs: the number of arguments passed to the function @@ -105,43 +104,43 @@ XPath function:</p><pre>/** */ typedef void (*xmlXPathEvalFunc)(xmlXPathParserContextPtr ctxt, - 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 -find one from the other:</p><ul><li>The function xsltXPathGetTransformContext provides this lookup facility: + 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 tofind +one from the other:</p><ul><li>The function xsltXPathGetTransformContext provides this lookup facility: <pre>xsltTransformContextPtr xsltXPathGetTransformContext (xmlXPathParserContextPtr ctxt);</pre> </li> - <li>The <code>xmlXPathContextPtr</code> associated to an - <code>xsltTransformContext</code> is stored in the <code>xpathCtxt</code> - field.</li> -</ul><p>The first thing an extension function may want to do is to check the -arguments passed on the stack, the <code>nargs</code> parameter will tell how -many of them were provided on the XPath expression. The macro valuePop will -extract them from the XPath stack:</p><pre>#include <libxml/xpath.h> + <li>The <code>xmlXPathContextPtr</code>associated to + an<code>xsltTransformContext</code>is stored in the + <code>xpathCtxt</code>field.</li> +</ul><p>The first thing an extension function may want to do is to check +thearguments passed on the stack, the <code>nargs</code>parameter will tell +howmany of them were provided on the XPath expression. The macro valuePop +willextract them from the XPath stack:</p><pre>#include <libxml/xpath.h> #include <libxml/xpathInternals.h> -xmlXPathObjectPtr obj = valuePop(ctxt); </pre><p>Note that <code>ctxt</code> is the XPath context not the XSLT one. It is -then possible to examine the content of the value. Check <a href="internals.html#Descriptio">the description of XPath objects</a> if -necessary. The following is a common sequence checking whether the argument -passed is a string and converting it using the built-in XPath -<code>string()</code> function if this is not the case:</p><pre>if (obj->type != XPATH_STRING) { +xmlXPathObjectPtr obj = valuePop(ctxt); </pre><p>Note that <code>ctxt</code>is the XPath context not the XSLT one. It +isthen possible to examine the content of the value. Check <a href="internals.html#Descriptio">the description of XPath +objects</a>ifnecessary. The following is a common sequence checking whether +the argumentpassed is a string and converting it using the built-in +XPath<code>string()</code>function if this is not the case:</p><pre>if (obj->type != XPATH_STRING) { valuePush(ctxt, obj); xmlXPathStringFunction(ctxt, 1); obj = valuePop(ctxt); -}</pre><p>Most common XPath functions are available directly at the C level and are -exported either in <code><libxml/xpath.h></code> or in -<code><libxml/xpathInternals.h></code>.</p><p>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:</p><pre>void * xsltGetExtData(xsltTransformContextPtr ctxt, - const xmlChar *URI);</pre><p>Again the URI to be provided is the one which was used when registering -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, - obj)</code></li> - <li>deallocate the parameters passed to the function using - <code>xmlXPathFreeObject(obj)</code></li> -</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 -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:</p><pre>/** +}</pre><p>Most common XPath functions are available directly at the C level and +areexported either in <code><libxml/xpath.h></code>or +in<code><libxml/xpathInternals.h></code>.</p><p>The extension function may also need to retrieve the data associated +tothis module instance (the database connection in the previous example) +thiscan be done using the xsltGetExtData:</p><pre>void * xsltGetExtData(xsltTransformContextPtr ctxt, + const xmlChar *URI);</pre><p>Again the URI to be provided is the one which was used when registeringthe +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,obj)</code></li> + <li>deallocate the parameters passed to the function + using<code>xmlXPathFreeObject(obj)</code></li> +</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-infunctions, including document(), key(), generate-id(), etc. as well +as a fullexample module at the end. Here is the test function implementation +for thelibxslt:test function:</p><pre>/** * xsltExtFunctionTest: * @ctxt: the XPath Parser context * @nargs: the number of arguments @@ -173,13 +172,14 @@ xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, int nargs) }</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, const xmlChar *name, const xmlChar *URI, - xsltTransformFunction function);</pre><p>It is similar to the mechanism used to register an extension function, -except that the signature of an extension element implementation is -different.</p><p>The registration is bound to a single transformation instance referred to -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).</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 -transformation function:</p><pre>/** + xsltTransformFunction function);</pre><p>It is similar to the mechanism used to register an extension +function,except that the signature of an extension element implementation +isdifferent.</p><p>The registration is bound to a single transformation instance referred +toby ctxt, name is the UTF8 encoded name for the NCName of the element, and +URIis the namespace name for the extension (no checking is done, a module +couldregister 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 +XSLTtransformation function:</p><pre>/** * xsltTransformFunction: * @ctxt: the XSLT transformation context * @node: the input node @@ -193,27 +193,27 @@ typedef void (*xsltTransformFunction) (xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, - xsltStylePreCompPtr comp);</pre><p>The first argument is the XSLT transformation context. The second and -third arguments are xmlNodePtr i.e. internal memory <a href="internals.html#libxml">representation of XML nodes</a>. They are -respectively <code>node</code> from the the input document being transformed -by the stylesheet and <code>inst</code> the extension element in the -stylesheet. The last argument is <code>comp</code> a pointer to a precompiled -representation of <code>inst</code> but usually for an extension function -this value is <code>NULL</code> by default (it could be added and associated -to the instruction in <code>inst->_private</code>).</p><p>The same functions are available from a function implementing an extension -element as in an extension function, including -<code>xsltGetExtData()</code>.</p><p>The goal of an 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 <a href="http://xmlsoft.org/html/libxml-tree.html"><libxml/tree.h></a> can -be employed to extend or modify the tree, but it is required to preserve the -insertion node and its ancestors since there are existing pointers to those -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 -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:</p><pre>/** + xsltStylePreCompPtr comp);</pre><p>The first argument is the XSLT transformation context. The second andthird +arguments are xmlNodePtr i.e. internal memory <a href="internals.html#libxml">representation of XML nodes</a>. They +arerespectively <code>node</code>from the the input document being +transformedby the stylesheet and <code>inst</code>the extension element in +thestylesheet. The last argument is <code>comp</code>a pointer to a +precompiledrepresentation of <code>inst</code>but usually for an extension +functionthis value is <code>NULL</code>by default (it could be added and +associatedto the instruction in <code>inst->_private</code>).</p><p>The same functions are available from a function implementing an +extensionelement as in an extension function, +including<code>xsltGetExtData()</code>.</p><p>The goal of an extension element being usually to enrich the +generatedoutput, it is expected that they will grow the currently generated +outputtree. This can be done by grabbing ctxt->insert which is the +currentlibxml node being generated (Note this can also be the intermediate +valuetree being built for example to initialize a variable, the processing +shouldbe similar). The functions for libxml tree manipulation from <a href="http://xmlsoft.org/html/libxml-tree.html"><libxml/tree.h></a>canbe +employed to extend or modify the tree, but it is required to preserve +theinsertion node and its ancestors since there are existing pointers to +thoseelements 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-inelements, including xsl:element, xsl:attribute, xsl:if, etc. There is +a smallbut full example in functions.c providing the implementation for +thelibxslt:test element, it will output a comment in the result tree:</p><pre>/** * xsltExtElementTest: * @ctxt: an XSLT processing context * @node: The current node @@ -253,10 +253,10 @@ xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNewComment((const xmlChar *) "libxslt:test element test worked"); xmlAddChild(ctxt->insert, comment); -}</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 -it exists) for each of the modules initialized is called. The -xsltExtShutdownFunction type defines the interface for a shutdown -function:</p><pre>/** +}</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 (ifit +exists) for each of the modules initialized is called. +ThexsltExtShutdownFunction type defines the interface for a +shutdownfunction:</p><pre>/** * xsltExtShutdownFunction: * @ctxt: an XSLT transformation context * @URI: the namespace URI for the extension @@ -266,14 +266,15 @@ function:</p><pre>/** */ typedef void (*xsltExtShutdownFunction) (xsltTransformContextPtr ctxt, const xmlChar *URI, - void *data);</pre><p>This is really similar to a module initialization function except a third -argument is passed, it's the value that was returned by the initialization -function. This allows the routine to deallocate resources from the module for -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> - <li>a better detection of extension functions usage and their registration - without having to use the extension prefix which ought to be reserved to - element extensions.</li> + void *data);</pre><p>This is really similar to a module initialization function except a +thirdargument is passed, it's the value that was returned by the +initializationfunction. This allows the routine to deallocate resources from +the module forexample 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> + <li>a better detection of extension functions usage and their + registrationwithout having to use the extension prefix which ought to be + reserved toelement extensions.</li> <li>more examples</li> - <li>implementations of the <a href="http://www.exslt.org/">EXSLT</a> common - extension libraries, Thomas Broyer nearly finished implementing them.</li> + <li>implementations of the <a href="http://www.exslt.org/">EXSLT</a>commonextension libraries, Thomas + Broyer nearly finished implementing them.</li> </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> |