You are viewing a plain text version of this content. The canonical link for it is here.
Posted to general@xml.apache.org by dl...@locus.apache.org on 2000/01/18 23:12:52 UTC

cvs commit: xml-site/sources/xalan extensions.xml

dleslie     00/01/18 14:12:52

  Added:       sources/xalan extensions.xml
  Log:
  Added document on support for XSLT extensions.
  
  Revision  Changes    Path
  1.1                  xml-site/sources/xalan/extensions.xml
  
  Index: extensions.xml
  ===================================================================
  <?xml version="1.0" standalone="no"?>
  <!--
   * Copyright (c) 1999 Lotus Development Corporation, Inc. All Rights Reserved.
   *	This software is provided without a warranty of any kind.
   *
  -->
  <!DOCTYPE s1 SYSTEM "sbk:/style/dtd/document.dtd">
  
  <s1 title="&xslt4j; Extensions">
     
  	 <s2 title="Introduction">
  <p>For those situations where you would like to augment the functionality of XSLT with calls to a procedural language, &xslt4j; supports the creation and use of extension elements and extension functions.</p>
  <p>You can set up &xslt4j; components to define extension elements and extension functions that call Java classes and Javascript scripts. In your XSL stylesheets, you can then use extension components to set script properties, for example, and extension functions to return values. &xslt4j; also provides a predefined "java" extension namespace that you can use to interact directly with Java objects.</p>
  <p>Furthermore, &xslt4j; ships with a propriatary extension that you can use to redirect the output of an XSL transformation to multiple files. This extension is implemented in the org.apache.xalan.xslt.extensions.Redirect class. Suggestions for extensions to add in future releases are more than welcome.</p>
  </s2>
  <s2 title="Supported languages">
  <p>&xslt4j; uses he Bean Scripting Framework (BSF), an architecture for incorporating scripting into Java
    applications and applets. Using BSF allows an application to take advantage of scripting while being
    independent of any specific scripting language. </p>
    <p>To use BSF, you must put two JAR files on the classpath: bsf.jar and bsfengine.jar. For JavaScript support, BSF has been tested with Mozilla Rhino 1.4 R3 js.jar, available from http://www.mozilla.org/rhino. We do not ship js.jar.</p>
  <table>
    <tr>
      <td><em>Language</em></td>
      <td><em>Version</em></td>
      <td><em>Dependencies</em></td>
    </tr>
    <tr>
      <td><p>Mozilla Rhino</p></td>
      <td><p>1.4 R3</p></td>
      <td><p>js.jar available from 
  				    http://www.mozilla.org/rhino</p></td>
    </tr>
    <tr>
      <td><p>NetRexx</p></td>
      <td><p>1.148 up </p></td>
      <td><p>NetRexxC.zip available from http://www2.hursley.ibm.com/netrexx</p></td>
    </tr>
      <tr>
      <td><p>BML</p></td>
      <td><p>2.4</p></td>
      <td><p>bmlall.jar available from http://www.alphaWorks.ibm.com/formula/bml</p></td>
    </tr>
      <tr>
      <td><p>JPython</p></td>
      <td><p>1.1-beta3</p></td>
      <td><p>python.jar available from http://www.jpython.org/</p></td>
    </tr>
      <tr>
      <td><p>Jacl</p></td>
      <td><p>1.1.1</p></td>
      <td><p> jacl.jar and tcljava.jar from http://www.scriptics.com/java</p></td>
    </tr>
      <tr>
      <td><p>Win32 ActiveScript langs
  	JScript, VBScript</p></td>
      <td><p></p></td>
      <td><p>MSVCP60.DLL from Microsoft, appropriate language DLLs from Microsoft 
      http://msdn.microsoft.com/scripting</p></td>
    </tr>
      <tr>
      <td><p>PerlScript</p></td>
      <td><p></p></td>
      <td><p>ActivePerl from http://www.activestate.com/</p></td>
    </tr>  
  </table>
  </s2>
  <s2 title="&xslt4j; components">
  
  <p>To set up extensions, do the following in an XSL stylesheet:</p>
  <ol>
    <li>Declare the &xslt4j; xslt namespace</li>
    <li>Declare a namespace for at least one extension prefix</li>
    <li>Use the extension-element-prefixes attribute on the xsl:stylesheet element, a literal result
    element, or another extension element to declare the extension namespace as an extension</li>
  </ol>
  <p>Then you can utilize the extension elements and associated extension functions in your stylesheet
  templates.</p>
  <p>To implement the extension, define a &xslt4j; component in the xslt namespace. A &xslt4j; component may be embedded within the stylesheet or maintained separately. The component contains the code that is called when the extension elements and functions are used.</p>
  <s3 title="&xslt4j; Component Syntax">
  <source>&lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;
                     xmlns:lxslt=&quot;http://xml.apache.org.xslt&quot;
                     xmlns:extn1=&quot;URI of extension namespace1&quot;
                     extension-element-prefixes=&quot;extn1 extn2&quot;&gt;
  
    &lt;xsl:template match=&quot;...&quot;&gt;
      ...
      &lt;extn1:element1 att1=&quot;value1&quot; att2=&quot;value2&quot; ...&gt;
        &lt;whatever-the-contents/&gt;
        &lt;including-xsl-elements/&gt;
      &lt;/extn1&gt;
      ...
      &lt;xsl:value-of select=&quot;extn1:function1(arg1,arg2,...,argn)&quot;/&gt;
      ...
    &lt;/xsl:template&gt;
  
    &lt;lxslt:component prefix=&quot;extn1&quot; elements=&quot;element1&quot; functions=&quot;function1&quot;&gt; 
      &lt;lxslt:script lang=&quot;javascript&quot;&gt;
        function element1 (xslProcContext, exensionElement) {
          code to do element1, including possibly evaluating the
          contents of the element by calling back to the processor
        }
  
        function function1 (arg1, arg2, ..., argn) {
          code to do function1
        }
      &lt;/lxslt:script&gt; 
    &lt;/lxslt:component&gt;
  &lt;/xsl:stylesheet&gt;</source>
  </s3>
  
  <s3 title="DTD for &xslt4j; Components">
  <source>&lt;!ELEMENT lxslt:component (lxslt:script)&gt;
  &lt;!ATTLIST lxslt:component
    prefix CDATA #IMPLIED
    namespace-uri CDATA #IMPLIED
    elements NMTOKENS #REQUIRED
    functions NMTOKENS #REQUIRED&gt;
  
  &lt;!ELEMENT lxslt:script EMPTY)&gt;
  &lt;!ATTLIST lxslt:script
    lang CDATA #REQUIRED
    src CDATA #IMPLIED&gt;</source>
  </s3>
  
  <p>For extension namespaces implemented using Java, a special
  convenience is supported which allows the programmer to skip the
  component specification. This is described later in the semantics
  of how a component description is located and loaded.</p>
  </s2>
  
  <s2 title="Locating &xslt4j; Components">
     <p>When &xslt4j; encounters the extension-element-prefixes attribute on a stylesheet, it uses the
        following algorithm to find and load the components to handle those extension namespaces:</p>
        <ol>
          <li> For each extension namespace, search for an &lt;<em>lxslt:component</em>&gt;
                  element with a <em>prefix</em> attribute whose
                  value matches the extension namespace prefix. If none is found, proceed to
                  step 2.</li>
              <li>Treat the URI of the namespace as a fully
                  qualified class name and attempt to
                  load that class. If the URI starts with
                  &quot;class:&quot;, strip that prefix
                  before attempting to load the class. If the class
                  loads, assume the following component description:
                  <source>  &lt;lxslt:component prefix=&quot;prefix-being-searched-for&quot;&gt; 
      &lt;lxslt:script lang=&quot;javaclass&quot; src=&quot;namespaceURI&quot;/&gt;
    &lt;/lxslt:component&gt;</source>  
                  <p>Assume, that is, a component implementation in Java
                  with a source URL value of the namespace URI
                  as the fully qualified class name. No elements and functions are defined -
                  which means that if one were to test this
                  namespace (via extension-element-available or
                  extension-function-available) then the tests
                  would fail. However, if a function or element is
                  invoked on this extension namespace the call
                  succeeds or fails depending on whether or not the
                  requisite functions (as defined below) were
                  defined by the class.</p>
              </li>
              <li>Treat the URI of the namespace as a URL and
                  attempt to load the component description
                  from this URL. If found and if the
                  lxslt:component has a &quot;namespace-uri&quot;
                  attribute present, it <em>must</em> match the
                  namespace URI of the extension specified in the
                  stylesheet. If no &quot;namespace-uri&quot;
                  attribute is present, the component is assumed to be the
                  component specification for this namespace. [NOT
                  FULLY IMPLEMENTED YET - NAMESPACE USAGE ISN'T
                  CORRECT.]<br/>
                  </li>
          </ol>
  
      <p>The component specification identifies the valid local
          parts of the extension namespace. The element and
          function local parts are identified separately using the <em>elements</em>
          and <em>functions</em> attributes, respectively. The
          component specification presents the code that implements
          these local parts using a &lt;<em>lxslt:script</em>&gt;
          element. The script element can inline the code or refer
          to an external source for the code using the <em>src</em>
          attribute.</p>
      <p>The currently supported languages are:
          &quot;javaclass&quot; and &quot;javascript&quot;, where
          &quot;javaclass&quot; is used to work with an
          implementation in Java and &quot;javascript&quot; refers
          to Netscape Rhino.</p>
      <p>Special case for lang=&quot;javaclass&quot;: The <em>src</em>
          attribute is treated as the fully qualified classname of
          the class which handles the extension namespace. If the
          name starts with &quot;<em>class:</em>&quot;,
          then the class is not instantiated and the methods
          invoked to handle various local parts (see below) are
          assumed to be static. Otherwise, a new instance is
          created and used for invoking the appropriate methods as
          defined below.</p>
      <p>The <em>src</em> attribute is not yet implemented for
          languages other than &quot;javaclass&quot;.</p>
      <p>For each extension element within the namespace, a
          function with the following signature must be defined in
          the implementation of the component:</p>
  <source>Object &lt;localPart&gt; (org.apache.xalan.xslt.XSLProcessorContext,
                        org.w3c.dom.Element extensionElement)</source>
          <p>where &lt;localPart&gt; is the local part of the
          extension element name. If the component is implemented
          in a loosely typed scripting language such as JavaScript,
          then these are untyped arguments to the function and the
          return type is unspecified as well. Note that for
          lang==&quot;javaclass&quot;, methods may be static or
          not-static and must be public in order to be accessible.</p>
      <p>When an extension element is invoked, the appropriate
          function (as identified above) is invoked to handle the
          invocation. The entire extension element is given as the
          second argument to the function with content, if any,
          as-is. Thus, if within an extension element one were to
          place elements from the xsl: namespace, then those would
          have to be processed by an explicit evaluation request from
          the extension element handler. Such invocations are done
          via the XSLProcessorContext object. [CALLING BACK INTO
          XSLProcessor.java NOT IMPLEMENTED YET.]</p>
      <p>For each extension function within the namespace, a
          function with the following signature must be defined in
          the implementation of the component:</p>
          <source>  Object &lt;localPart&gt; (Type1 arg1, Type2 arg2, ..., Typen argn)</source>
          <p>where &lt;localPart&gt; is the local part of the
          extension function name. The type of each argument
          depends on what was given within XSLT in the invocation
          of the function. Here is the mapping from an XSLT data
          type to the Java data types that are used in invoking the
          methods:</p>
          <table>
              <tr>
                  <th>XSLT Type</th>
                  <th>Java Type</th>
              </tr>
              <tr>
                  <td>Node-Set</td>
                  <td>org.w3c.dom.NodeList</td>
              </tr>
              <tr>
                  <td>String</td>
                  <td>java.lang.String</td>
              </tr>
              <tr>
                  <td>Boolean</td>
                  <td>boolean or Boolean</td>
              </tr>
              <tr>
                  <td>Number</td>
                  <td>double or Double</td>
              </tr>
              <tr>
                  <td>Result Tree Fragment</td>
                  <td>org.w3c.dom.DocumentFragment</td>
              </tr>
              <tr>
                  <td>variable</td>
                  <td>one of above based on <br/>
                  type of variable's value</td>
              </tr>
          </table>
          <p>For boolean and number XSLT types,
          first all such types are converted to the corresponding
          primitive type in Java and the method searched for. If
          the method is not found, then a method with the object
          types is searched for. For example foo:bar('a'='b', 1,
          'Hello', 2) would first look for a method
          bar(boolean,double,String,boolean) and then for
          bar(Boolean,Double,String,Double).</p>
          <p>If the component is implemented in a loosely typed
          scripting language such as JavaScript, then these are
          untyped arguments to the function and the return type is
          unspecified as well.</p>
      <p>When an extension function is invoked, the appropriate
          function (as identified above) is invoked to handle the
          invocation. Any arguments to the function are first
          evaluated and then the resulting values are passed to the
          function by first converting them according to the table
          listed above.</p>
      <p>To control how a stylesheet behaves if an extension is not available, create an xsl:fallback element with 
         xsl:choose or xsl:if instructions and the element-available and extension-available functions.</p>
  </s2>
  <s2 title="Special Handling for Extensions into Java">
  
  <p>When a qualified function name is invoked, if the
  namespace is not already registered as an extension namespace (by
  the above mechanism), &xslt4j; treats the URI of the namespace as a fully qualified class
  name and attempts to load that class. If the URI starts
  with &quot;class:&quot;, &xslt4j; strips that prefix before
  attempting to load the class. If class loading succeeds, then an
  extension namespace implemented in &quot;javaclass&quot; is
  assumed with the URI as the value of the src attribute. Note that
  no functions are defined - which means that if one were to test
  this namespace (via extension-function-available) then the tests
  would fail. However, if a function is invoked on this extension
  namespace, the call succeeds or fails depending on whether or not the
  requisite functions (as defined above) were defined by the class.</p>
  </s2>
  <s2 title="Predefined Extension Namespace for Java Access">
  <p>&xslt4j; supports a special namespace for convenient
  interaction with Java objects. The namespace URI is &quot;http://xsl.lotus.com/java&quot;.
  This namespace allows the stylesheet author to create new
  instances of Java classes and to invoke static and non-static
  methods on them. Assuming, the namespace declaration &quot;<em>xmlns:java='http://xsl.lotus.com/java'</em>&quot;
  is in scope, the following are supported:</p>
  <p>java:<ref>FQCN</ref>.<em>new</em> (<ref>args</ref>)</p>
  
  <p>where FQCN is the fully qualified class name of which a new
  instance is to be created with the given constructor arguments
  (if any).</p>
  
  <p>java:<ref>FQCN.methodName</ref> (<ref>args</ref>)</p>
  
  <p>where <ref>FQCN</ref> is the fully qualified class name whose
  static method &quot;<ref>methodName</ref>&quot; is to be invoked
  using the given arguments. </p>
  
  <p>java:<ref>methodName</ref> (<ref>object</ref>, <ref>args</ref>)</p>
  
  <p>where <ref>methodName</ref> is the name of the (static or
  non-static) method to invoke on <ref>object</ref> with the given
  arguments.</p>
  </s2>
  <s2 title="Passing Nodes to java">
  <p>If you want to pass one or more Nodes to an extension function, set up a Java method to accept an 
  org.w3c.dom.NodeList (or an org.apache.xalan.xpath.MutableNodeList, which extends NodeList, if you want to modify the Nodes).</p>
  <p>When you call an extension function with an argument that constitutes a pattern match for one or more Nodes, the &xslt4j; extension mechanism evaluates this argument as a NodeList, even if only one Node is involved.</p>
  <p>Suppose, for example, you have a myExtensions.ProcessNodes class with the following doSomething method:</p>
  <p><code>doSomething(org.w3c.dom.NodeList nList)</code></p>
  <p>Any of the following extension calls in a stylesheet are syntatically possible:</p>
  <p><code>java:MyExtensions.ProcessNodes.doSomething(.) &lt;!-- current node --></code></p>
  <p><code>java:MyExtensions.ProcessNodes.doSomething(*) &lt;!-- all nodes in current context--></code></p>
  <p><code>java:MyExtensions.ProcessNodes.doSomething(/*) &lt;!-- all nodes --></code></p>
  <p><code>java:MyExtensions.ProcessNodes.doSomething(foo/baz) &lt;!-- foo/baz nodes in current context --></code></p>
  <p><code>java:MyExtensions.ProcessNodes.doSomething(/foo/baz | /bar/saz) &lt;!-- /foo/baz and /bar/saz nodes --></code></p>
  <p>The NodeList 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, wich may not be the next Node in the NodeList.</p>
  </s2>
  <s2 title="Example 1: Named Counter Component in Java">
  
  <p>MyCounter.java:</p>
  
  <source>  import java.util.*;
  
  public class MyCounter {
    Hashtable counters = new Hashtable ();
  
    public MyCounter () {
    }
  
    // the context arg is actually a org.apache.xalan.xslt.XSLProcessorContext
    public void init (Object context, org.w3c.dom.Element elem) {
      String name = elem.getAttribute (&quot;name&quot;);
      String value = elem.getAttribute (&quot;value&quot;);
      int val;
      try {
        val = Integer.parseInt (value);
      } catch (NumberFormatException e) {
        e.printStackTrace ();
        val = 0;
      }
      counters.put (name, new Integer (val));
    }
  
    public int read (String name) {
      Integer cval = (Integer) counters.get (name);
      return (cval == null) ? 0 : cval.intValue ();
    }
  
    public void incr(Object context, org.w3c.dom.Element elem) {
      String name = elem.getAttribute (&quot;name&quot;);
      Integer cval = (Integer) counters.get (name);
      int nval = (cval == null) ? 0 : (cval.intValue () + 1);
      counters.put (name, new Integer (nval));
    }
  }</source>
  
  <p>MyFamily.xml:</p>
  
  <source>&lt;?xml version=&quot;1.0&quot;?&gt;
  
  &lt;doc&gt;
    &lt;name first=&quot;Sanjiva&quot; last=&quot;Weerawarana&quot;/&gt;
    &lt;name first=&quot;Shahani&quot; last=&quot;Weerawarana&quot;/&gt;
    &lt;name first=&quot;Rukmal&quot; last=&quot;Weerawarana&quot;/&gt;
    &lt;name first=&quot;Sashi&quot; last=&quot;Weerawarana&quot;/&gt;
    &lt;name first=&quot;Kamal&quot; last=&quot;Fernando&quot;/&gt;
    &lt;name first=&quot;Ruby&quot; last=&quot;Fernando&quot;/&gt;
  &lt;/doc&gt;</source>
  
  <p>Counter.xsl:</p>
  
  <source>&lt;?xml version=&quot;1.0&quot;?&gt; 
  
  &lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;
                  xmlns:lxslt=&quot;http://xsl.lotus.com/&quot;
                  xmlns:counter=&quot;MyCounter&quot;
                  extension-element-prefixes=&quot;counter&quot;&gt;
  
    &lt;!-- note that the component definition is optional because I
         used the fully qualified class name of the implementation
         as the URI for this namespace. --&gt;
    &lt;lxslt:component prefix=&quot;counter&quot;
                     elements=&quot;init incr&quot; functions=&quot;read&quot;&gt;
      &lt;lxslt:script lang=&quot;javaclass&quot; src=&quot;MyCounter&quot;/&gt;
    &lt;/lxslt:component&gt;
  
    &lt;xsl:template match=&quot;/&quot;&gt;
      &lt;HTML&gt;
        &lt;H1&gt;Test for namespace specified Java extension.&lt;/H1&gt;
        &lt;counter:init name=&quot;index&quot; value=&quot;1&quot;/&gt;
        &lt;p&gt;Here are the names in alphabetical order by last name:&lt;/p&gt;
        &lt;xsl:for-each select=&quot;doc/name&quot;&gt;
          &lt;xsl:sort select=&quot;@last&quot;/&gt;
          &lt;xsl:sort select=&quot;@first&quot;/&gt;
          &lt;p&gt;
          &lt;xsl:text&gt;[&lt;/xsl:text&gt;
          &lt;xsl:value-of select=&quot;counter:read('index')&quot;/&gt;
          &lt;xsl:text&gt;]. &lt;/xsl:text&gt;
          &lt;xsl:value-of select=&quot;@last&quot;/&gt;
          &lt;xsl:text&gt;, &lt;/xsl:text&gt;
          &lt;xsl:value-of select=&quot;@first&quot;/&gt;
          &lt;/p&gt;
          &lt;counter:incr name=&quot;index&quot;/&gt;
        &lt;/xsl:for-each&gt;
      &lt;/HTML&gt;
    &lt;/xsl:template&gt;
   
  &lt;/xsl:stylesheet&gt;</source>
  
  <p>Output:</p>
  
  <source>&lt;HTML&gt;
    &lt;H1&gt;Test for namespace specified Java extension.&lt;/H1&gt;
    &lt;p&gt;Here are the names in alphabetical order by last name, first name:&lt;/p&gt;
    &lt;p&gt;[1]. Fernando, Kamal&lt;/p&gt;
    &lt;p&gt;[2]. Fernando, Ruby&lt;/p&gt;
    &lt;p&gt;[3]. Weerawarana, Rukmal&lt;/p&gt;
    &lt;p&gt;[4]. Weerawarana, Sanjiva&lt;/p&gt;
    &lt;p&gt;[5]. Weerawarana, Sashi&lt;/p&gt;
    &lt;p&gt;[6]. Weerawarana, Shahani&lt;/p&gt;
  &lt;/HTML&gt;</source>
  </s2>
  <s2 title="Example 2: Named Counter Component Implemented Using Java
  XPath Extension Namespace">
  
  <p>Counter.xsl:</p>
  
  <source>&lt;?xml version=&quot;1.0&quot;?&gt; 
  
  &lt;!-- named counter functionality done using java: --&gt;
  
  &lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;
                  xmlns:java=&quot;http://xsl.lotus.com/java&quot;&gt;
  
    &lt;xsl:template match=&quot;/&quot;&gt;
      &lt;HTML&gt;
        &lt;H1&gt;Test for namespace specified Java extension.&lt;/H1&gt;
        &lt;xsl:variable name=&quot;counter-table&quot; 
                      select=&quot;java:java.util.Hashtable.new ()&quot;/&gt;
        &lt;!-- do following for side-effect --&gt;
        &lt;xsl:if test=&quot;java:put ($counter-table, 'index', 1)&quot;/&gt;
        &lt;p&gt;Here are the names in alphabetical order by last name, first name:&lt;/p&gt;
        &lt;xsl:for-each select=&quot;doc/name&quot;&gt;
          &lt;xsl:sort select=&quot;@last&quot;/&gt;
          &lt;xsl:sort select=&quot;@first&quot;/&gt;
          &lt;p&gt;
          &lt;xsl:text&gt;[&lt;/xsl:text&gt;
          &lt;xsl:value-of select=&quot;java:get ($counter-table, 'index')&quot;/&gt;
          &lt;xsl:text&gt;]. &lt;/xsl:text&gt;
          &lt;xsl:value-of select=&quot;@last&quot;/&gt;
          &lt;xsl:text&gt;, &lt;/xsl:text&gt;
          &lt;xsl:value-of select=&quot;@first&quot;/&gt;
          &lt;/p&gt;
          &lt;!-- do following for side-effect --&gt;
          &lt;xsl:if test=&quot;java:put ($counter-table, 'index',
                                  java:get($counter-table,'index')+1)&quot;/&gt;
        &lt;/xsl:for-each&gt;
      &lt;/HTML&gt;
    &lt;/xsl:template&gt;
   
  &lt;/xsl:stylesheet&gt;</source>
  
  <p>Produces the same results.</p>
  </s2>
  <s2 title="Example 3: Redirecting transformation output to multiple files">
  <p>For information on using the Redirect extension to send output to mulitple files, see <resource-ref idref="RedirectDoc"/>.</p>
  </s2>
  </s1>