| <?xml version="1.0" standalone="no"?> |
| <!-- |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| --> |
| <!DOCTYPE s1 SYSTEM "../../style/dtd/document.dtd"> |
| |
| <s1 title="&xslt4c; Extension Functions"> |
| <ul> |
| <li><link anchor="intro">Introduction</link></li> |
| <li><link anchor="implement">Implementing an extension function</link></li> |
| <li><link anchor="install">Installing an extension function</link></li> |
| <li><link anchor="use">Using an extension function</link></li> |
| </ul> |
| <anchor name="intro"/> |
| <s2 title="Introduction"> |
| <p>At times, you may want to call your own custom C functions from a stylesheet. For these situations, &xslt4c; supports the |
| creation and use of extension functions. &xslt4c; also provides a <link idref="extensionslib">library of extension functions |
| </link> for your use.</p> |
| <p>You can think of extension functions as extending the core library of functions that XPath provides. Like the |
| XPath functions, an extension function returns an XObject, which may contain a value of any of the five XSLT |
| data types: node-set, result-tree-fragment, string, boolean, or number.</p> |
| <p>You can send arguments to an extension function in the form of XPath expressions, literals (for string, boolean, and number), |
| the values returned by other functions, and XSL variables or parameters set to any of the preceding.</p> |
| <p>For an example that implements, installs, and uses three extension functions, see the |
| <link idref="samples" anchor="externalfunctions">External Functions</link> sample.</p> |
| <note>&xslt4c; does not support extension elements.</note> |
| </s2> |
| |
| <anchor name="implement"/> |
| <s2 title="Implementing an extension function"> |
| <p>Like the standard XPath functions, the functions you create derive from the Function base class. Set up your |
| extension function class as follows:</p> |
| <ol> |
| <li>The body of a function is the execute() method. Use the appropriate XObjectFactory method -- createNumber() |
| in the example below -- to create an XObject corresponding to the XSLT data type the function returns.<br/><br/></li> |
| <li>Implement a clone() method to enable Xalan to create and maintain a copy of the extension |
| function.<br/><br/></li> |
| <li>(Optional) As Xalan does for the XPath functions, you may want to prevent the compiler from generating |
| an assignment or equality operator for this function.</li> |
| </ol> |
| <p>These features all appear in the following example.</p> |
| <source> |
| // Base header file. Must be first. |
| #include <xalanc/Include/PlatformDefinitions.hpp> |
| |
| #include <cmath> |
| #include <ctime> |
| |
| #include <xercesc/util/PlatformUtils.hpp> |
| #include <xalanc/XalanTransformer/XalanTransformer.hpp> |
| #include <xalanc/XPath/XObjectFactory.hpp> |
| |
| using namespace xalanc; |
| |
| // This class defines a function that will return the square root |
| // of its argument. |
| class FunctionSquareRoot : public Function |
| { |
| public: |
| |
| /** |
| * Execute an XPath function object. The function must return a valid |
| * XObject. |
| * |
| * @param executionContext executing context |
| * @param context current context node |
| * @param opPos current op position |
| * @param args vector of pointers to XObject arguments |
| * @return pointer to the result XObject |
| */ |
| virtual XObjectPtr |
| execute( |
| XPathExecutionContext& executionContext, |
| XalanNode* /* context */, |
| const XObjectPtr arg, |
| const Locator* /* locator */) const |
| { |
| if (args.size() != 1) |
| { |
| executionContext.error("The square-root() function takes one argument!", |
| context); |
| } |
| assert(args[0] != 0); |
| // Use the XObjectFactory createNumber() method to create an XObject |
| // corresponding to the XSLT number data type. |
| return executionContext.getXObjectFactory().createNumber( |
| sqrt(args[0]->num())); |
| } |
| |
| /** |
| * Implement clone() so Xalan can copy the square-root function into |
| * its own function table. |
| * |
| * @return pointer to the new object |
| */ |
| virtual FunctionSquareRoot* |
| clone() const |
| { |
| return new FunctionSquareRoot(*this); |
| } |
| |
| private: |
| // The assignment and equality operators are not implemented... |
| FunctionSquareRoot& |
| operator=(const FunctionSquareRoot&); |
| bool |
| operator==(const FunctionSquareRoot&) const; |
| } |
| </source> |
| </s2> |
| <anchor name="install"/> |
| <s2 title="Installing an extension function"> |
| <p><jump href="apiDocs/classXalanTransformer.html">XalanTransformer</jump> provides methods for installing and uninstalling external functions:</p> |
| <ul> |
| <li>installExternalFunction() makes the function available in the current instance of XalanTransformer. Use uninstallExternalFunction() to remove the function.<br/><br/></li> |
| <li>installExternalFunctionGlobal() makes the function available globally. Use uninstallExternalFunctionGlobal() to remove the function. The global install and uninstall operations are not thread-safe. However, all global functions should be thread-safe, because multiple threads could call a particular function instance at the same time.</li> |
| </ul> |
| <p>These methods include arguments for the namespace, the function name, and the function implementation.</p> |
| <p>When you install an extension function, the function inhabits the namespace you designate. For information about XML namespaces, see <jump href="http://www.w3.org/TR/REC-xml-names/">Namespaces in XML</jump>.</p> |
| <p>The following code fragment installs locally the square root function defined above, and binds it to the extension-function name "square-root" in the namespace "http://MyExternalFunction.mycompany.org" so it can be accessed from stylesheets. Keep in mind that the function name does not need to be the same as the name of the function class, and that a function name may be used more than once provided that each function with that name is installed in a different namespace.</p> |
| <source>#include <xalanc/Include/PlatformDefinitions.hpp> |
| #include <xercesc/util/PlatformUtils.hpp> |
| #include <xalanc/XalanTransformer/XalanTransformer.hpp> |
| // You have created a header file for FunctionSquareRoot. |
| #include <MyFunctions/FunctionSquareRoot.hpp> |
| // The namespace... |
| const XalanDOMString |
| theNamespace("http://MyExternalFunction.mycompany.org"); |
| |
| theXalanTransformer.installExternalFunction(theNamespace, |
| XalanDOMString("square-root"), |
| FunctionSquareRoot());</source> |
| <p>For an example that installs three functions, see the <link idref="samples" anchor="externalfunctions">External Functions</link> sample.</p> |
| </s2> |
| <anchor name="use"/> |
| <s2 title="Using an extension function"> |
| <p>To use the extension function in a stylesheet, you must do the following:</p> |
| <ol> |
| <li>Declare the extension function namespace.<br/><br/> |
| <code>xmlns:<ref>prefix</ref>=<ref>URI</ref></code><br/><br/> |
| The <ref>prefix</ref> identifies the namespace, and <ref>URI</ref> matches the namespace specified when the function |
| is installed.<br/><br/> |
| By default, namespace declarations are included in the transformation output. To exclude namespaces from the output, |
| use<br/><br/> |
| <code>exclude-result-prefixes="<ref>prefix-1 prefix-2 ...</ref>"</code><br/><br/> |
| in the stylesheet element or<br/><br/> |
| <code>xsl:exclude-result-prefixes="<ref>prefix-1 prefix-2 ...</ref>"</code><br/><br/> |
| in a literal result element or extension element.<br/><br/></li> |
| <li>Call the extension function in the same manner you would call an XPath function. The function name you use in the stylesheet is a Qualified Name (QName) made up of the prefix you declared in step 1 and the function name you specified when you installed the function.<br/><br/> |
| You can use XPath expressions, literals (for string, boolean, and number), and values returned by other functions to |
| specify function arguments.</li></ol> |
| <p>Suppose, for example, you are working with XML documents containing area elements like |
| <code><area value="397"/></code>, where the value attribute identifies the area of a square.</p> |
| <p>The following stylesheet declares the square-root function namespace (the prefix is up to you), instructs |
| the processor not to copy the namespace declaration to the result tree, and uses the square-root function to return |
| the square root of //area/@value:</p> |
| <source> |
| <?xml version="1.0"?> |
| <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" |
| version="1.0" |
| xmlns:external="http://ExternalFunction.xalan-c.xml.apache.org" |
| exclude-result-prefixes="external"> |
| |
| <xsl:template match="//area"> |
| <out> |
| The area of the square is |
| <xsl:value-of select="@value"/> square units. |
| The length of each side is |
| <xsl:value-of select="external:square-root(@value)"/> units |
| </out> |
| </source> |
| <p>This stylesheet converts <code><area value="397"/></code> into the following output:</p> |
| <source><out> |
| The area of the square is |
| 397 square units. |
| The length of each side is |
| 19.9249 units. |
| </out> |
| </source> |
| <p>For a slightly more complex variation on this example, |
| see the <link idref="samples" anchor="externalfunctions">External Functions</link> sample.</p> |
| <s3 title="Passing Nodes to a function"> |
| <p>Please keep in mind that <em>all</em> LocationPath expressions return a node-set, even if the expression only |
| returns a single attribute or a text node (node-sets with one member). You can use the XSLT string() function |
| to convert a node-set value to string, and the number() function to convert a node-set value to number (a double).</p> |
| <p>If you pass a node-set to an extension function, be sure to set up the function to process a node-set.</p> |
| <p>Suppose, for example, you have a ProcessNodes function class that uses<br/><br/> |
| <code>const NodeRefListBase& theNodeList = args[0]->nodeset();</code><br/><br/> |
| in the execute() method to get a reference to the node-set.</p> |
| <p>Assuming you install the function as "ProcessNodes" and use the "node-ext" prefix in a stylesheet to refer to the ProcessNodes function namespace, any of the following function calls are syntactically possible:</p> |
| <p><code><!--Process the current node--></code><br/> |
| <code><xsl:variable name="success" select="node-ext:ProcessNodes(.)"/></code></p> |
| <p><code><!--Process all nodes in current context--></code><br/> |
| <code><xsl:variable name="success" select="node-ext:ProcessNodes(*)"/></code></p> |
| <p><code><!-- Process all nodes --></code><br/> |
| <code><xsl:variable name="success" select="node-ext:ProcessNodes(/*)"/></code></p> |
| <p><code><!--Process the foo/baz nodes in current context --></code><br/> |
| <code><xsl:variable name="success" select="node-ext:ProcessNodes(foo/baz)"/></code></p> |
| <p><code><!--Process the/foo/baz and /bar/saz nodes --></code><br/> |
| <code><xsl:variable name="success" select="node-ext:ProcessNodes(/foo/baz | /bar/saz)"/></code></p> |
| <p>The NodeRefListBase is in fact a list of references into the XML document, so keep in mind that getNextSibling(), |
| for example, gets you the next sibling in the document, which may not be the next Node in the node-set.</p> |
| </s3> |
| </s2> |
| </s1> |