| <?xml version="1.0" standalone="no"?> |
| <!DOCTYPE s1 SYSTEM "../../style/dtd/document.dtd"> |
| <!-- |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 2001 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xalan" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 2001, Sun |
| * Microsystems., http://www.sun.com. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| --> |
| <s1 title="<xsl:variable> / <xsl:param>"> |
| |
| <s2 title="Contents"> |
| <ul> |
| <li><link anchor="functionality">Functionality</link></li> |
| <li><link anchor="implementation">Implementation</link></li> |
| </ul> |
| </s2> |
| |
| <anchor name="functionality"/> |
| <s2 title="Functionality"> |
| |
| <p>Variables in XSLT are not really variables, as their values cannot be |
| changed. They resemble constants from conventional programming languages. The |
| only way in which a variable can be changed is by declaring it inside a |
| for-each loop, in which case its value will be updated for every iteration. |
| Top-level variables (variables that are direct child nodes of the |
| <code><xsl:stylesheet></code> element) can never be changed.</p> |
| |
| <source> |
| <xsl:for-each select="/foo/bar"> |
| <xsl:variable name="some-bar" select="."/> |
| <xsl:value-of select="$some-bar"/> |
| </xsl:for-each></source> |
| |
| <p>Parameters are assigned a value either from the process that invoked |
| the stylesheet (top-level parameter), or from a |
| <code><xsl:with-param></code> or from a default value (in which case it |
| behaves as if it was a variable).</p> |
| |
| <source> |
| <xsl:template match="/"> |
| <xsl:call-template name="blob"> |
| <xsl:with-param name="par" select="'some-value'"/> |
| </xsl:call-template> |
| </xsl:template> |
| |
| <xsl:template name="blob"> |
| <xsl:param name="par" select="'default-value'"/> |
| <xsl:value-of select="$param"/> |
| </xsl:template></source> |
| |
| </s2> |
| |
| <anchor name="implementation"/> |
| <s2 title="Implementation"> |
| |
| <p>Variables and parameters share a common base class |
| <code>VariableBase</code> that contains a lot of common methods. This class |
| handles both global and local variables/parameters.</p> |
| |
| <s3 title="Top-level parameters and variables"> |
| |
| <p>All top-level (ie. global) parameters and variables are stored inside |
| fields in the translet class. Variables are stored as objects or basic |
| data types (such as boolean, char, int, etc.) while parameters have to be |
| "boxed" inside an object. This is because parameters are also stored as |
| objects inside the translet. The <code>addParameter()</code> method of the |
| <code>AbstractTranslet</code> class stores the parameter in a Hashtable |
| (the Hashtable maps the parameter name to the parameter value). The |
| "boxing" of the parameter's value is done by the class that handles the |
| parameters type. This class is a subclass of |
| <code>org.apache.xalan.xsltc.compiler.util.Type</code>.</p> |
| |
| <p>Note that all top-level parameters and variables from all imported and |
| included stylesheets will be placed as direct children of the top-level |
| stylesheet in the AST. This done to make global variables truly global and |
| not just global in the stylesheet where it was declared.</p> |
| |
| </s3> |
| |
| <s3 title="Local parameters and variables"> |
| |
| <p>Local variables that are accessible from a given syntax tree node will |
| first be put on the JVM's stack and stored in a local variable slot. This |
| makes the variable or parameter accessible from all code within that |
| method. But, in some special cases, the code that is compiled to handle an |
| element/expression within the variable scope is not put inside the same |
| method as the actual variable. This is the case for some predicates. |
| All syntax-tree nodes implement the <code>isClosureBoundary()</code> method |
| to indicate if its child an ancestor nodes will end up in a different method |
| then itself. This method is used by the <code>Variable</code> and |
| <code>Param</code> classes to determine if the variable or parameter will |
| "escape" the variable frame.</p> |
| |
| <source> |
| <xsl:for-each select="/foo/bar/baz"> |
| <xsl:variable name="pos" select="3"/> |
| <xsl:apply-templates select="/foo/bar[$pos]"/> |
| </xsl:for-each></source> |
| |
| <p>The predicate in this stylesheet fragment is compiled into a separate |
| auxiliary class that implements the <code>Filter</code> interface. It will |
| therefore not have access to the variable "pos" in the current stack frame. |
| A common technique for cases like this is to use a <em>"closure"</em>. A |
| closure is a record that contains references to all variables that are in |
| scope for a certain part of the compiled scope. This is done in a very |
| simple manner in XSLTC. All variables or parameters that can "escape" the |
| stack are passed to the translet via its <code>addVariable()</code> method. |
| They can then later be retrieved by the <code>getVariable()</code> method. |
| </p> |
| |
| <p><em>Important note 1:</em> A predicate does not always result in a |
| auxiliary class. In some cases we optimize the code by using tailored |
| iterators and goodies like that instead. We may want to update the |
| predicate code to check if an auxiliary class will be generated before |
| returning true or false from the <code>isClosureBoundary()</code> |
| method.</p> |
| |
| <p><em>Important note 2:</em> There could be other closure boundaries |
| that we have not yet discovered or considered. This could be, for instance, |
| sort records and other auxiliary classes:</p> |
| |
| <source> |
| <xsl:variable name="sort-order" select="'decending'"/> |
| <xsl:for-each select="/foo/bar/baz"> |
| <xsl:sort select="@name" order="$sort-order"/> |
| <xsl:value-of select="."/> |
| </xsl:for-each></source> |
| |
| <p>I would not be surprised if this fails. A fix could be to implement the |
| <code>isClosureBoundary()</code> in the <code>Sort</code> class and have the |
| method return 'true' in all cases.</p> |
| |
| </s3> |
| |
| <s3 title="Parameter and variable references"> |
| |
| <p>A parameter or variable reference does the oposite of a parameter or |
| variable. The value is read from either a global field, a local variable |
| slot or from a call to <code>getVariable()</code> / |
| <code>getParameter()</code>. The chosen method depends is we're dealing with |
| a parameter or a variable, a global or a local, an escaping variable or not. |
| </p> |
| |
| <p>The XPath parser identifies all variable references and instanciates |
| either a <code>VariableRef</code> or a <code>ParameterRef</code>. The XPath |
| parser calls the parser's <code>lookupVariable</code> method in an initial |
| attempt to find the variable/parameter instance. If that fails, it goes on |
| to call the symbol table's <code>lookupName()</code> method. If that also |
| fails this means that either:</p> |
| |
| <ul> |
| <li>a variable or parameter with the given name does not exist</li> |
| <li>the variable will be declared at a later stage |
| (but within the same scope)</li> |
| </ul> |
| |
| <p>The XPath parser creates an instance of the <code>UnresolvedRef</code> |
| class. This class attempts to locate the variable after the whole AST has |
| been built, when the <code>typeCheck()</code> method is called. If this |
| fails an error is reported and the compilation stops. Otherwise the class |
| creates a <code>VariableRef</code> or a <code>ParameterRef</code> instance |
| and lets that handle the reference.</p> |
| |
| </s3> |
| |
| <s3 title="Forward references"> |
| |
| <p>XSLTC allows for forward references to global variables and parameters. |
| You can even reference variables in not-yet included/imported stylesheets. |
| In most cases, this is handled by changing the order of top-level elements. |
| (Variables are placed first so that they are handled before any includes |
| or imports). But when a variable contains references to other variables, |
| then this requires some extra code in the <code>Stylesheet</code> and |
| <code>VariableBase</code> classes. The <code>VariableBase</code> has a |
| method that returns a vector containing all variables that are referenced |
| in the variable definition.</p> |
| |
| <source> |
| <xsl:variable name="C" select="$A < $B"/> |
| <xsl:variable name="A" select="1"/> |
| <xsl:variable name="B" select="2"/></source> |
| |
| <p>In this case, the <code>getDependencies()</code> method for variable |
| C will return the variables A and B. The stylesheet has a method called |
| <code>resolveReferences</code> that will order the variables accordingly |
| so that the variable values are computed in the desired order. This method |
| will issue an error message and terminate the compilation if there are |
| circular variable/parameter dependencies.</p> |
| |
| </s3> |
| |
| </s2> |
| |
| </s1> |