You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by dl...@apache.org on 2001/05/04 22:20:47 UTC
cvs commit: xml-xalan/java/xdocs/sources/xsltc DOMInterface.gif DOMLocking.gif all_namespaces.gif cast_expression.gif compiler_AST.gif compiler_DOM.gif compiler_architecture.gif dom_namespace1.gif dom_namespace2.gif dom_namespace3.gif index.xml key_relations.gif match_namespace1.gif match_namespace2.gif namespace_stack.gif output_namespaces1.gif output_namespaces2.gif pattern_objects.gif runtime_architecture.gif runtime_type_mapping.gif sort_objects.gif type_mapping.gif type_mappings.gif typecast.gif xsl_comment_design.xml xsl_key_design.xml xsl_lang_design.xml xsl_sort_design.xml xsl_unparsed_design.xml xsl_whitespace_design.xml xsltc_compiler.xml xsltc_dom.xml xsltc_namespace.xml xsltc_runtime.xml xsltover.xml
dleslie 01/05/04 13:20:47
Added: java/xdocs/sources/xsltc DOMInterface.gif DOMLocking.gif
all_namespaces.gif cast_expression.gif
compiler_AST.gif compiler_DOM.gif
compiler_architecture.gif dom_namespace1.gif
dom_namespace2.gif dom_namespace3.gif index.xml
key_relations.gif match_namespace1.gif
match_namespace2.gif namespace_stack.gif
output_namespaces1.gif output_namespaces2.gif
pattern_objects.gif runtime_architecture.gif
runtime_type_mapping.gif sort_objects.gif
type_mapping.gif type_mappings.gif typecast.gif
xsl_comment_design.xml xsl_key_design.xml
xsl_lang_design.xml xsl_sort_design.xml
xsl_unparsed_design.xml xsl_whitespace_design.xml
xsltc_compiler.xml xsltc_dom.xml
xsltc_namespace.xml xsltc_runtime.xml xsltover.xml
Log:
Transformed Morten Jorgensen's XSLTC design documents
to XML.
Adding to repository with accompanying .gif files.
Revision Changes Path
1.1 xml-xalan/java/xdocs/sources/xsltc/DOMInterface.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/DOMLocking.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/all_namespaces.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/cast_expression.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/compiler_AST.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/compiler_DOM.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/compiler_architecture.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/dom_namespace1.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/dom_namespace2.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/dom_namespace3.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/index.xml
Index: index.xml
===================================================================
<?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="Introduction to XSLTC">
<p><ref>Design documents by <jump href="mailto:morten@xml.apache.org">Morten Jørgensen</jump>
- updated 06.03.2001</ref></p>
<ul>
<li><link anchor="compiler">Compiler design</link></li>
<li><link anchor="runtime">Runtime library/DOM design</link></li>
</ul>
<anchor name="compiler"/>
<s2 title="Compiler design">
<p><link idref="xsltc_compiler"><img src="compiler_architecture.gif" alt="compiler_architecture.gif"/></link></p>
<p><ref>Figure 1: Compiler architecture overview</ref></p>
<p>Click on the picture to jump to the overall design document for the compiler.</p>
<p>Each XSL element/function and XPath expression/pattern is represented by
its own class in the Abstract Syntax Tree (AST). Some of these classes have
their own design documents (I am working on the rest of them):</p>
<s3 title="XSL elements">
<ul>
<li>
<link idref="xsl_whitespace_design"><xsl:preserve-space>/<xsl:strip-space></link>
</li>
<li>
<link idref="xsl_sort_design"><xsl:sort></link>
</li>
<li>
<link idref="xsl_key_design"><xsl:key></link>
</li>
<li>
<link idref="xsl_comment_design"><xsl:comment>/<xsl:message></link>
</li>
</ul>
</s3>
<s3 title="XSL functions">
<ul>
<li>
<link idref="xsl_key_design">key()</link>
</li>
<li>
<link idref="xsl_lang_design">lang()</link>
</li>
<li>
<link idref="xsl_unparsed_design">unparsed-entity-uri()</link>
</li>
</ul>
</s3>
</s2><anchor name="runtime"/>
<s2 title="Runtime library/DOM design">
<p><link idref="xsltc_runtime"><img src="runtime_architecture.gif" alt="runtime_architecture.gif"/></link></p>
<p><ref>Figure 2: Runtime library architecture overview</ref></p>
<p>Click on the picture to jump to the overall design document for the XSLTC
runtime library. This document describes the structure of the compiled
translet as well as the translet runtime library.</p>
<p>The <link idref="xsltc_dom">Internal DOM</link> describes the components and structure of the internal DOM,
support for DOM2 navigation, the DOM adapter, DOM multiplexer, and DOM builder.</p>
<p><link idref="xsltc_namespace">Namespaces</link> explains how XSLTC (including the compiler) handles
namespaces.</p>
</s2>
</s1>
1.1 xml-xalan/java/xdocs/sources/xsltc/key_relations.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/match_namespace1.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/match_namespace2.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/namespace_stack.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/output_namespaces1.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/output_namespaces2.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/pattern_objects.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/runtime_architecture.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/runtime_type_mapping.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/sort_objects.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/type_mapping.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/type_mappings.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/typecast.gif
<<Binary file>>
1.1 xml-xalan/java/xdocs/sources/xsltc/xsl_comment_design.xml
Index: xsl_comment_design.xml
===================================================================
<?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:comment> / <xsl:message>">
<ul>
<li><link anchor="functionality">Functionality</link></li>
<li><link anchor="implementation">Implementation</link></li>
</ul>
<anchor name="functionality"/>
<s2 title="Functionality">
<p>The <code><xsl:comment></code> element is used to insert XML comments
into the result document. The comment is inserted as follows in the XSL
stylesheet:</p>
<source> <element>
<xsl:comment>This is a comment!</xsl:comment>
</element></source>
<p>and it will be output in the result document as follows:</p>
<source> <element>
<!-- This is a comment! -->
</element></source>
<p>The <code><xsl:message></code> element is used to send messages to
who/whatever is performing the transformation. The message can be displayed
in a terminal, a dialog box, etc. The <code><xsl:message></code> element
is used in the same way as the <code><xsl:comment></code> element,
however the message is <em>not</em> output in the result document.</p>
<p>The <code><xsl:message></code> element has an attribute
<code>"terminate"</code> which can be used to terminate the transformation at any
given stage. This is useful when using message to give information about
illegal values in the input document.</p>
</s2><anchor name="implementation"/>
<s2 title="Implementation">
<p>The output handler class has a method for outputting comments in the
output document and messages to the operator. The code compiled for a
comment gathers all text that goes into the comment in a StringValueHandler
object, retrieves the full text string from this handler, and then finally
sends it to the output handler. Similarly the code compiled for a message
will simply send the message to the output handler in use.</p>
<p>Messages will be output to the terminal (stdout) when a transformation
is run in a terminal. The message will be output before the beginning of the
output document. Messages will be shown in a dialog box if a transformation
is run in an applet.</p>
<p><code><xsl:message></code> elements that use the <code>"terminate"</code>
attribute to abort transformations cause an exception to be thrown. A
RuntimeException is used for this, and the exception text is:</p>
<p><code>Termination forced by an xsl:message instruction</code></p>
</s2>
</s1>
1.1 xml-xalan/java/xdocs/sources/xsltc/xsl_key_design.xml
Index: xsl_key_design.xml
===================================================================
<?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:key> / key() / KeyPattern">
<ul>
<li><link anchor="functionality">Functionality</link></li>
<li><link anchor="implementation">Implementation</link></li>
</ul>
<anchor name="functionality"/>
<s2 title="Functionality">
<p>The <code><xsl:key></code> element is a top-level element that can be
used to define a named index of nodes from the source XML tree(s). The
element has three attributes:</p>
<ul>
<li>
<code>name</code> - the name of the index
</li>
<li>
<code>match</code> - a pattern that defines the nodeset we want
indexed
</li>
<li>
<code>use</code> - an expression that defines the value to be used
as the index key value.
</li>
</ul>
<p>A named index can be accessed using either the <code>key()</code> function or
a KeyPattern. Both these methods address the index using its defined name
(the "name" attribute above) and a parameter defining one or more lookup
values for the index. The function or pattern returns a node set containing
all nodes in the index whose key value match the parameter's value(s):</p>
<source>
<xsl:key name="book-author" match="book" use="author"/>
:
:
<xsl:for-each select="key('book-author', 'Mikhail Bulgakov')">
<xsl:value-of select="author"/>
<xsl:text>: </xsl:text>
<xsl:value-of select="author"/>
<xsl:text>&#xa;</xsl:text>
</xsl:for-each>
</source>
<p>The KeyPattern can be used within an index definition to create unions
and intersections of node sets:</p>
<source>
<xsl:key name="cultcies" match="farmer | fisherman" use="name"/>
</source>
<p>This could of course be done using regular <code><xsl:for-each></code>
and <code><xsl:select></code> elements. However, if your stylesheet
accesses the same selection of nodes over and over again, the transformation
will be much more efficient using pre-indexed keys as shown above.</p>
</s2><anchor name="implementation"/>
<s2 title="Implementation">
<p>AbstractTranslet has a global hashtable that holds an index for each named
key in the stylesheet (hashing on the "name" attribute of xsl:key).
AbstractTranslet has a couple of public methods for inserting and retrieving
data from this hashtable:</p>
<source>
public void buildKeyIndex(String name, int nodeID, String value);
public KeyIndex KeyIndex getKeyIndex(String name);
</source>
<p>The Key class compiles code that traverses the input DOM and extracts
nodes that match some given parameters (the <code>"match"</code> attribute of the
<code><xsl:key></code> element). A new element is inserted into the named
key's index. The nodes' DOM index and the value translated from the
<code>"use"</code> attribute of the <code><xsl:key></code> element are stored
in the new entry in the index.</p>
<p>The index itself is implemented in the <code>KeyIndex</code> class.
The index has an hashtable with all the values from the matching nodes (the
part of the node used to generate this value is the one specified in the
<code>"use"</code> attribute). For every matching value there is a Vector
holding a list of all node indexes for which this value gives a match:</p>
<p><img src="key_relations.gif" alt="key_relations.gif"/></p>
<p><ref>Figure 1: Indexing tables</ref></p>
<p>The <code>KeyIndex</code> class implements the <code>NodeIterator</code>
interface, so that it can be returned directly by the implementation of the
<code>key()</code> function. This is how the index generated by
<code><xsl:key></code> and the node-set returned by the <code>key()</code> and
KeyPattern are tied together. You can see how this is done in the
<code>translate()</code> method of the <code>KeyCall</code> class.</p>
<p>The <code>key()</code> function can be called in two ways:</p>
<source>
key('key-name','value')
key('key-name','node-set')
</source>
<p>The first parameter is always the name of the key. We use this value to
lookup our index from the _keyIndexes hashtable in AbstractTranslet:</p>
<source>
il.append(classGen.aloadThis());
_name.translate(classGen, methodGen);
il.append(new INVOKEVIRTUAL(getKeyIndex));
</source>
<p>This compiles into a call to
<code>AbstractTranslet.getKeyIndex(String name)</code>, and it leaves a
<code>KeyIndex</code> object on the stack. What we then need to do it to
initialise the <code>KeyIndex</code> to give us nodes with the requested value.
This is done by leaving the <code>KeyIndex</code> object on the stack and pushing
the <code>"value"</code> parameter to <code>key()</code>, before calling
<code>lookup()</code> on the index:</p>
<source>
il.append(DUP); // duplicate the KeyIndex obejct before return
_value.translate(classGen, methodGen);
il.append(new INVOKEVIRTUAL(lookup));
</source>
<p>This compiles into a call to <code>KeyIndex.lookup(String value)</code>. This
will initialise the <code>KeyIndex</code> object to return nodes that match the
given value, so the <code>KeyIndex</code> object can be left on the stack when
we return. This because the <code>KeyIndex</code> object implements the
<code>NodeIterator</code> interface.</p>
<p>This matter is a bit more complex when the second parameter of
<code>key()</code> is a node-set. In this case we need to traverse the nodes in
the set and do a lookup for each node in the set. What I do is this:</p>
<ul>
<li>
construct a <code>KeyIndex</code> object that will hold the return node-set
</li>
<li>
find the named <code>KeyIndex</code> object from the hashtable in
AbstractTranslet
</li>
<li>
get an iterator for the node-set and do the folowing loop:</li>
<ul>
<li>get string value for current node</li>
<li>do lookup in KeyIndex object for the named index</li>
<li>merge the resulting node-set into the return node-set</li>
</ul>
<li>
leave the return node-set on stack when done
</li>
</ul>
<p>The only work that remains is to update the <code>merge()</code> method of
the <code>KeyIndex</code> class so that it eliminates duplicate nodes in the
resulting node-set.</p>
</s2>
</s1>
1.1 xml-xalan/java/xdocs/sources/xsltc/xsl_lang_design.xml
Index: xsl_lang_design.xml
===================================================================
<?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="lang() function">
<ul>
<li><link anchor="functionality">Functionality</link></li>
<li><link anchor="implementation">Implementation</link></li>
</ul>
<anchor name="functionality"/>
<s2 title="Functionality">
<p>The <code>xml:lang</code> can be used to determine the language for a node or
a node-set. The attribute can be used to store language-specific data in an
XML document:</p>
<source>
<phrases>
<greeting xml:lang="en">Hello!</greeting>
<greeting xml:lang="no">Hei!</greeting>
<greeting xml:lang="fr">Salut!</greeting>
<greeting xml:lang="es">Hola!</greeting>
<greeting xml:lang="de">Sweinhund!</greeting>
</phrases>
</source>
<p>The XSL stylesheet can use the <code>lang()</code> function to select the
element with the desired language:</p>
<source>
<xsl:template match="greeting">
<xsl:if test="lang("de")>
<xsl:value-of select="."/>
<xsl:text> Grossglucklicher wunche!</xsl:text>
</xsl:if>
</xsl:template>
</source>
</s2> <anchor name="implementation"/>
<s2 title="Implementation">
<p>The DOM interface has been given a method that returns the language for
a given node. The language is returned as a string (on whatever format is
used in the XML document - should be iso), and may be null if no language is
defined.</p>
<source>
public String DOM.getLanguage(int node);
</source>
<p>The BasisLibrary class has a static method that will compare the language
of the context node with some other language and return the result as a
boolean.</p>
<source>
public static boolean BasisLibrary.testLanguage(String language, DOM dom, int node);
</source>
<p>The compiled code for the <code>lang()</code> method calls this method in the
BasisLibrary and leaves the result on the stack for the calling element.</p>
</s2>
</s1>
1.1 xml-xalan/java/xdocs/sources/xsltc/xsl_sort_design.xml
Index: xsl_sort_design.xml
===================================================================
<?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:sort>">
<ul>
<li><link anchor="functionality">Functionality</link></li>
<li><link anchor="sort-class">The Sort class</link></li>
<li><link anchor="sortingiterator-class">The SortingIterator class</link></li>
<li><link anchor="nodesortrecord-class">The NodeSortRecord class</link></li>
<li><link anchor="nodesortrecordfactory-class">The NodeSortRecordFactory class</link></li>
</ul>
<anchor name="functionality"/>
<s2 title="Functionality">
<p>The <code><xsl:sort></code> element is used to define a sort key which
specifies the order in which nodes selected by either
<code><xsl:apply-templates></code> or <code><xsl:for-each></code> are
processed. The nodes can be sorted either in numerical or alphabetic order,
and the alphabetic order may vary depeinding on the language in use. The
nodes can be sorted either in ascending or descending order.</p>
</s2><anchor name="sort-class"/>
<s2 title="The Sort class">
<p>Static methods of the Sort class is responsible for generating the
necessary code for invoking SortingIterators under
<code><xsl:apply-templates></code> and <code><xsl:for-each></code>
elements. Both these elements can have several <code><xsl:sort></code>
child nodes defining primary, secondary, teriary, etc. keys. The code for
<code><xsl:apply-templates></code> and <code><xsl:for-each></code>
create vectors containg a Sort object for each sort key. The object methods
of the Sort object encapsulate a container for key-specific data (such as the
sort key itself, sort order, sort type, and such) while the static methods
take a vector of Sort objects and generate the actual code.</p>
<p>The <code>translate()</code> method of the Sort object is never called. The
vectors containing the Sort objects for a <code><xsl:apply-templates></code>
or <code><xsl:for-each></code> element are instead passed to the static
<code>translateSortIterator()</code> method. This method compiles code that
instanciates a SortingIterator object that will pass on a node-set in a
specific order to the code handling the <code><xsl:apply-templates></code>
or <code><xsl:for-each></code> element.</p>
</s2><anchor name="sortingiterator-class"/>
<s2 title="The SortingIterator class">
<p>The SortingIterator class is responsible for sorting nodes encapsulated in
sort obects. These sort objects must be of a class inheriting from
NodeSortRecord, a the SortingIterator object needs a factory object providing
it with the correct type of objects:</p>
<p><img src="sort_objects.gif" alt="sort_objects.gif"/></p>
<p><ref>Figure 1: SortingIterator</ref></p>
<p>The SortingIterator class is fairly dumb and leaves much of the work to the
NodeSortRecord class. The iterator gets the NodeSortRecords from the factory
object and sorts them using quicksort and calling <code>compareTo()</code> on
pairs of NodeSortRecord objects.</p>
</s2><anchor name="nodesortrecord-class"/>
<s2 title="The NodeSortRecord class">
<p>The static methods in the Sort class generates a class inheriting from
NodeSortRecord, with the following overloaded methods:</p>
<ul>
<li><em>Class Constructor</em></li>
<ul><li>The class constructor is overloaded to create sort-key global
tables, such as an array containing the sort order for all the sort keys
and another array containg all the sort types. Different sort order/types
can be specified for the different levels of sort keys, but we assume that
the same language is used for all levels.</li></ul>
<li><code>extractValueFromDOM(int level)</code></li>
<ul><li>This method is called by the SortingIterator object to extract the
value for a specific sort key for a node. The SortingIterator will only
use this method once and will cache the returned value for later use. The
method will only be called if absultely necessary.</li></ul>
<li><code>compareType(int level)</code></li>
<ul><li>This method returns the sort type for one sort key level. Returns
either <code>COMPARE_STRING</code> or <code>COMPARE_NUMERIC</code>.</li></ul>
<li><code>sortOrder(int level)</code></li>
<ul><li>This method returns the sort order for one sort key level. Returns
either <code>COMPARE_ASCENDING</code> or <code>COMPARE_DESCENDING</code></li></ul>
<li><code>getCollator(int level)</code></li>
<ul><li>This method returns a Collator object for language-specific
string comparisons. The same Collator is used for all levels of the key.
</li></ul>
</ul>
<p>The <code>compareTo()</code> method of the NodeSortRecord base class deserves
a bit of attention. It takes its own node (from the this pointer) and another
node and compares, if necessary, the values for all sort keys:</p>
<source>
/**
* Compare this sort element to another. The first level is checked first,
* and we proceed to the next level only if the first level keys are
* identical (and so the key values may not even be extracted from the DOM)
*/
public int compareTo(NodeSortRecord other) {
int cmp;
for (int level=0; level<_levels; level++) {
// Compare the two nodes either as numeric or text values
if (compareType(level) == COMPARE_NUMERIC) {
final Double our = numericValue(level);
final Double their = other.numericValue(level);
if (our == null) return(-1);
if (their == null) return(1);
cmp = our.compareTo(their);
}
else {
String our = stringValue(level);
String their = other.stringValue(level);
if (our == null) return(-1);
if (their == null) return(1);
cmp = getCollator().compare(our,their);
}
// Return inverse compare value if inverse sort order
if (cmp != 0) {
if (sortOrder(level) == COMPARE_DESCENDING)
return(0 - cmp);
else
return(cmp);
}
}
return(0);
}
</source>
<p>The two methods <code>stringValue(int level)</code> and
<code>numericValue(int level)</code> return values for one level of the sort key
of a node. These methods cache these values after they are first read so that
the <code>DOM.getNodeValue()</code> is only called once. Also, the algorithm
used for these two methods assure that <code>DOM.getNodeValue()</code> is only
called when needed. The value for a node's secondary sort key is never
retrieved if the node can be uniquely identified by its primary key.</p>
</s2><anchor name="nodesortrecordfactory-class"/>
<s2 title="The NodeSortRecordFactory class">
<p>After the static methods of the Sort class has generated the new class for
sort objects it generates code that instanciates a new NodeSortRecordFactory
object. This object is passed as a parameter to SortingIterators constructor
and is used by the iterator to generate the necessary sort objects.</p>
</s2>
</s1>
1.1 xml-xalan/java/xdocs/sources/xsltc/xsl_unparsed_design.xml
Index: xsl_unparsed_design.xml
===================================================================
<?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="unparsed-entity-uri()">
<ul>
<li><link anchor="functionality">Functionality</link></li>
<li><link anchor="implementation">Implementation</link></li>
</ul>
<anchor name="functionality"/>
<s2 title="Functionality">
<p>The <code>unparsed-entity-uri()</code> function gives access to declarations
of unparsed entities in the DTD of the source document. If the DTD contains
the declaration:</p>
<source>
<!ENTITY mom-picture SYSTEM "http://www.home.com/mom.jpg" NDATA JPEG>
</source>
<p>the expression <code>unparsed-entity-uri('mom-picture')</code> returns an
URI for the file <code>mom.jpg</code>.</p>
</s2><anchor name="implementation"/>
<s2 title="Implementation">
<p>Unparsed entities must be gathered from the XML input document at the time
when the DOM is built. To achieve this our parser must parse the document DTD
(if any) and store all data of type NDATA (not XML data) in a
hashtable in the AbstractTranslet object. All the compiled code for this
function needs to do is call a method in the translet for retrieving the
value for the requested element:</p>
<source>
public String AbstractTranslet.getUnparsedEntity(String entityName);
</source>
<p>The translet will use the supplied <code>entityName</code> to look up the
value in the hashtable and then leave the string value on the stack for the
element that called <code>lang()</code>.</p>
</s2>
</s1>
1.1 xml-xalan/java/xdocs/sources/xsltc/xsl_whitespace_design.xml
Index: xsl_whitespace_design.xml
===================================================================
<?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:strip/preserve-space>">
<ul>
<li><link anchor="functionality">Functionality</link></li>
<li><link anchor="identify">Identifying strippable whitespace nodes</link></li>
<li><link anchor="which">Determining which nodes to strip</link></li>
<li><link anchor="strip">Stripping nodes</link></li>
<li><link anchor="filter">Filtering whitespace nodes</link></li>
</ul>
<anchor name="functionality"/>
<s2 title="Functionality">
<p>The <code><xsl:strip-space></code> and <code><xsl:preserve-space></code>
elements are used to control the way whitespace nodes in the source XML
document are handled. These elements have no impact on whitespace in the XSLT
stylesheet. Both elements can occur only as top-level elements, possible more
than once, and the elements are always empty</p>
<p>Both elements take one attribute "elements" which contains a
whitespace separated list of named nodes which should be or preserved
stripped from the source document. These names can be on one of these three
formats (NameTest format):</p>
<ul>
<li>
All whitespace nodes:
<code>elements="*"</code>
</li>
<li>
All whitespace nodes with a namespace:
<code>elements="<namespace>:*"</code>
</li>
<li>
Specific whitespace nodes: <code>elements="<qname>"</code>
</li>
</ul>
</s2><anchor name="identify"/>
<s2 title="Identifying strippable whitespace nodes">
<p>The DOM detects all text nodes and assigns them the type <code>TEXT</code>.
All text nodes are scanned to detect whitespace-only nodes. A text-node is
considered a whitespace node only if it consist entirely of characters from
the set { 0x09, 0x0a, 0x0d, 0x20 }. The DOM implementation class has a static
method used to detect such nodes:</p>
<source>
private static final boolean isWhitespaceChar(char c) {
return c == 0x20 || c == 0x0A || c == 0x0D || c == 0x09;
}
</source>
<p>The characters are checked in proable order.</p>
<p> The DOM has a bit-array that is used to tag text-nodes as strippable
whitespace nodes:</p>
<source>private int[] _whitespace;</source>
<p>There are two methods in the DOM implementation class for accessing this
bit-array: <code>markWhitespace(node)</code> and <code>isWhitespace(node)</code>.
The array is resized together with all other arrays in the DOM by the
<code>DOM.resizeArrays()</code> method. The bits in the array are set in the
<code>DOM.maybeCreateTextNode()</code> method. This method must know whether
the current node is a located under an element with an
<code>xml:space="<value>"</code> attribute in the DOM, in which
case it is not a strippable whitespace node.</p>
<p>An auxillary class, WhitespaceHandler, is used for this purpose. The class
works in a way as a stack, where you "push" a new strip/preserve setting
together with the node in which this setting was determined. This means that
for every time the DOM builder encounters an <code>xml:space</code> attribute
it will invoke a method on an instance of teh WhitespaceHandler class to
signal that a new preserve/strip setting has been encountered. This is done
in the <code>makeAttributeNode()</code> method. The whitespace handler stores the
new setting and pushes the current element node on its stack. When the
DOM builder closes up an element (in <code>endElement()</code>), it invokes
another method of the whitespace handler to check if the strip/preserve
setting is still valid. If the setting is now invalid (we're closing the
element whose node id is on the top of the stack) the handler inverts the
setting and pops the element node id off the stack. The previous
strip/preserve setting is then valid, and the id of node where this setting
was defined is on the top of the stack.</p>
</s2><anchor name="which"/>
<s2 title="Determining which nodes to strip">
<p>A text node is never stripped unless it contains only whitespace
characters (Unicode characters 0x09, 0x0A, 0x0D and 0x20). Stripping a text
node means that the node disappears from the DOM; so that it is never
included in the output and that it is ignored by all functions such as
<code>count()</code>. A text node is preserved if any of the following apply:</p>
<ul>
<li>
the element name of the parent of the text node is in the set of
elements listed in <code><xsl:preserve-space></code>
</li>
<li>
the text node contains at least one non-whitespace character
</li>
<li>
an ancenstor of the whitespace text node has an attribute of
<code>xsl:space="preserve"</code>, and no close ancestor has and
attribute of <code>xsl:space="default"</code>.
</li>
</ul>
<p>Otherwise, the text node is stripped. Initially the set of
whitespace-preserving element names contains all element names, so the
default behaviour is to preserve all whitespace text nodes.</p>
<p>This seems simple enough, but resolving conflicts between matching
<code><xsl:strip-space></code> and <code><xsl:preserve-space></code>
elements requires a lot of thought. Our first consideration is import
precedence; the match with the highest import precedence is always chosen.
Import precedence is determined by the order in which the compared elements
are visited. (In this case those elements are the top-level
<code><xsl:strip-space></code> and <code><xsl:preserve-space></code>
elements.) This example is taken from the XSLT recommendation:</p>
<ul>
<li>stylesheet A imports stylesheets B and C in that order;</li>
<li>stylesheet B imports stylesheet D;</li>
<li>stylesheet C imports stylesheet E.</li>
</ul>
<p>Then the order of import precedence (lowest first) is D, B, E, C, A.</p>
<p>Our next consideration is the priority of NameTests (XPath spec):</p>
<ul>
<li>
<code>elements="<qname>"</code> has priority 0
</li>
<li>
<code>elements="<namespace>:*"</code> has priority -0.25
</li>
<li>
<code>elements="*"</code> has priority -0.5
</li>
</ul>
<p>It is considered an error if the desicion is still ambiguous after this,
and it is up to the implementors to decide what the apropriate action is.</p>
<p>With all this complexity, the normal usage for these elements is quite
smiple; either preserve all whitespace nodes but one type:</p>
<source><xsl:strip-space elements="foo"/></source>
<p>or strip all whitespace nodes but one type:</p>
<source>
<xsl:strip-space elements="*"/>
<xsl:preserve-space elements="foo"/></source>
</s2><anchor name="strip"/>
<s2 title="Stripping nodes">
<p>The ultimate goal of our design would be to totally screen all stripped
nodes from the translet; to either physically remove them from the DOM or to
make it appear as if they are not there. The first approach will cause
problems in cases where multiple translets access the same DOM. In the future
we wish to let translets run within servlets / JSPs with a common DOM cache.
This DOM cache will keep copies of DOMs in memory to prevent the same XML
file from being downloaded and parsed several times. This is a scenarios we
might see:</p>
<p><img src="DOMInterface.gif" alt="DOMInterface.gif"/></p>
<p><ref>Figure 1: Multiple translets accessing a common pool of DOMs</ref></p>
<p>The three translets running on this host access a common pool of 4 DOMs.
The DOMs are accessed through a common DOM interface. Translets accessing
a single DOM will have a DOMAdapter and a single DOMImpl object behind this
interface, while translets accessing several DOMs will be given a MultiDOM
and a set of DOMImpl objects.</p>
<p>The translet to the left may want to strip some nodes from the shared DOM
in the cache, while the other translets may want to preserve all whitespace
nodes. Our initial thought then is to keep the DOM as it is and somehow
screen the left-hand translet of all the whitespace nodes it does not want to
process. There are a few ways in which we can accomplish this:</p>
<ul>
<li>
The translet can, prior to starting to traverse the DOM, send a reference
to the tables containing information on which nodes we want stripped to
the DOM interface. The DOM interface is the responsible for hiding all
stripped whitespace nodes from the iterators and the translet. A problem
with this approach is that we want to omit the DOM interface layer if
the translet is only accessing a single DOM. The DOM interface layer will
only be instanciated by the translet if the stylesheet contained a call
to the <code>document()</code> function.<br/><br/>
</li>
<li>
The translet can provide its iterators with information on which nodes it
does not want to see. The translet is still shielded from unwanted
whitespace nodes, but it has the hassle of passing extra information over
to most iterators it ever instanciates. Note that all iterators do not
need be aware of whitepspace nodes in this case. If you have a look at
the figure again you will see that only the first level iterator (that is
the one closest to the DOM or DOM interface) will have to strip off
whitespace nodes. But, there may be several iterators that operate
directly on the DOM ( invoked by code handling XSL functions such as
<code>count()</code>) and every single one of those will need to be told
which whitespace nodes the translet does not want to see.<br/><br/>
</li>
<li>
The third approach will take advantage of the fact that not all
translets will want to strip whitespace nodes. The most effective way of
removing unwanted whitespace nodes is to do it once and for all, before
the actual traversal of the DOM starts. This can be done by making a
clone of the DOM with exlusive-access rights for this translet only. We
still gain performance from the cache because we do not have to pay the
cost of the delay caused by downloading and parsing the XML source file.
The cost we have to pay is the time needed for the actual cloning and the
extra memory we use.<br/><br/>
Normally one would imagine the translet (or the wrapper class that
invokes the translet) calls the DOM cache with just an URL and receives
a reference to an instanciated DOM. The cache will either have built
this DOM on-demand or just passed back a reference to an existing tree.
In this case the DOM would need an extra call that a translet would use
to clone a DOM, passing the existing DOM reference to the cache and
recieving a new reference to the cloned DOM. The translet can then do
whatever it wants with this DOM (the cache need not even keep a reference
to this tree).
</li>
</ul>
<p>We are lucky enough to be able to combine the first two approaches. All
iterators that directly access the DOM (axis iterators) are instanciated by
calls to the DOM interface layer (the DOM class). The actual iterators are
created in the DOM implementation layer (the DOMImpl class). So, we can pass
references to the preserve/strip whitespace tables to the DOM, and the DOM
will make sure that all axis iterators return node sets with respect to these
tables.</p>
</s2><anchor name="filter"/>
<s2 title="Filtering whitespace nodes">
<p>For each axis iterator and for <code>DOM.makeStringValue()</code> and
<code>DOM.stringValueAux()</code> we must apply a filter for eliminating all
unwanted whitespace nodes. To achive this we must build a very efficient
predicate for determining if the current node should be stripped or not. This
predicate is built by <code>Whitespace.compilePredicate()</code>. This method is
static and builds a predicate for a vector of WhitespaceRule objects. (The
WhitespaceRule class is defined within the Whitespace class.) Each
WhitespaceRule object contains information for a single element listed
in an <code><xsl:strip/preserve-space></code> element, and is broken down
into the following information:</p>
<ul>
<li>the namespace (can be the default namespace)</li>
<li>the element name or "<code>*</code>"</li>
<li>the type of rule; NS:EL, NS:<code>*</code> or <code>*</code></li>
<li>the priority of the rule (based on import precedence and type)</li>
<li>the action; either strip or preserver</li>
</ul>
<p>The Vector of WhitespaceRules is arranged in order of priority and
redundant rules are removed. A predicate method is then compiled into the
translet as:</p>
<source>
public boolean stripSpace(int node);
</source>
<p>Unfortunately this method cannot be declared static.</p>
<p>When the Stylesheet objectcompiles the <code>topLevel()</code> method of the
translet it checks for the existance of the <code>stripSpace()</code> method. If
this method exists the <code>topLevel()</code> will be compiled to pass the
translet to the DOM as a StripWhitespaceFilter (the translet implements this
interface when the <code>stripSpace()</code> method is compiled).</p>
<p>All axis iterators and the <code>DOM.makeStringValue()</code> and
<code>DOM.stringValueAux()</code> methods check for the existance of this filter
(it is kept in a global variable in the DOM implementation class) and takes
the appropriate actions. The methods in the DOM for returning axis iterators
will place a StrippingIterator on top of the axis iterator if the filter is
present, and the two methods just mentioned will return empty strings for
whitespace nodes that should be stripped.</p>
</s2>
</s1>
1.1 xml-xalan/java/xdocs/sources/xsltc/xsltc_compiler.xml
Index: xsltc_compiler.xml
===================================================================
<?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="XSLTC Compiler Design">
<ul>
<li><link anchor="overview">Compiler Overview</link></li>
<li><link anchor="ast">Building an Abstract Syntax Tree</link></li>
<li><link anchor="typecheck">Type-check and Cast Expressions</link></li>
<li><link anchor="compile">Code generation</link></li>
</ul>
<anchor name="overview"/>
<s2 title="Compiler overview">
<p>The input stylesheet is parsed using the SAX 1-based parser from Sun's
Project X:</p>
<ul>
<li><code>com.sun.xml.parser.Parser</code></li>
</ul>
<p>This parser builds a DOM from the stylesheet document, and hands this
DOM over to the compiler. The compiler uses its own specialised parser to
parse XPath expressions and patterns:</p>
<ul>
<li><code>com.sun.xslt.compiler.XPathParser</code></li>
</ul>
<p>Both parsers are encapsulates in XSLTC's parser class:</p>
<ul>
<li><code>com.sun.xslt.compiler.Parser</code></li>
</ul>
</s2><anchor name="ast"/>
<s2 title="Building an Abstract Syntax Tree">
<ul>
<li><link anchor="mapping">Mapping stylesheet elements to Java classes</link></li>
<li><link anchor="domxsl">Building a DOM tree from the input XSL file</link></li>
</ul>
<p>The SAX parser builds a standard W3C DOM from the source stylesheet.
This DOM does not contain all the information needed to represent the
whole stylesheet. ( Remember that XSL is two languages; XML and XPath.
The DOM only covers XML. ) The compiler uses the DOM to build an
abstract syntax tree (AST) that contains all the nodes from the DOM, plus
additional nodes for the XPath expressions.</p>
<anchor name="mapping"/>
<s3 title="Mapping stylesheets elements to Java classes">
<p>Each XSL element is represented by a class in the
<code>com.sun.xslt.compiler</code> package. The Parser class contains a
Hashtable that that maps XSL instructions to classes that inherit from a
common parent class 'Instruction' (which again inherits from
'SyntaxTreeNode'). This mapping is set up in the <code>initClasses()</code> method:</p>
<source> private void initStdClasses() {
try {
initStdClass("template", "Template");
initStdClass("param", "Param");
initStdClass("with-param", "WithParam");
initStdClass("variable", "Variable");
initStdClass("output", "Output");
:
:
:
}
}
private void initClass(String elementName, String className)
throws ClassNotFoundException {
_classes.put(elementName,
Class.forName(COMPILER_PACKAGE + '.' + className));
}</source>
</s3><anchor name="domxsl"/>
<s3 title="Building a DOM tree from the input XSL file">
<p>The parser instanciates a DOM that holds the input XSL stylesheet. The
DOM can only handle XML files and will not break up and identify XPath
patterns/expressions (these are stored as attributes to the various
nodes in the tree) or calls to XSL functions(). Each XSL instruction gets
its own node in the DOM, and the XPath patterns/expressions are stored as
attributes of these nodes. A stylesheet looking like this:</p>
<source>
<xsl:stylesheet .......>
<xsl:template match="chapter">
<xsl:text>Chapter</xsl:text>
<xslvalue-of select=".">
</xsl:template>
</xsl>stylesheet>
</source>
<p>will be stored in the DOM as indicated in the following picture:</p>
<p><img src="compiler_DOM.gif" alt="compiler_DOM.gif"/></p>
<p><ref>Figure 1: DOM containing XSL stylesheet</ref></p>
<p>The pattern '<code>match="chapter"</code>' and the expression
'<code>select="."</code>' are stored as attributes for the nodes
'<code>xsl:template</code>' and '<code>xsl:value-of</code>' respectively.
These attributes are accessible through the DOM interface.</p>
</s3>
<s3 title="Creating the Abstract Syntax Tree from the DOM">
<p>What we have to do next is to create a tree that also holds the XSL
specific elements; XPath expressions and patters (with possible filters)
and calls to XSL functions. This is done by parsing the DOM and creating an
instance of a subclass of 'SyntaxTreeNode' for each node in the DOM. A node
in the DOM containing an XSL instruction (ex. "xsl:template") results in an
instance of the correspoding class derived from the HashTable created by
the parser (in this case in instance of the 'Template' class).</p>
<p>Each class that inherits SyntaxTreeNode has a vector called
'<code>_contents</code>' that holds references to all the children of the node
(if any). Each node has a method called '<code>parseContents()</code>'. It is
the responsibility of this method to parse any XPath expressions/patterns
that are expected and found in the node's attributes. The XPath patterns
and instructions are tokenised using the auto-generated class 'XPathParser'
(generated using JavaCup and JLex). The tokenised expressions/patterns
will result in a small sub-tree owned by the syntax tree node.</p>
<p>XSL nodes holding expressions has a pointer called '<code>_select</code>' that
points to a sub-tree representing the expression. This can be seen for
instance in the 'Template' class:</p>
<p><img src="compiler_AST.gif" alt="compiler_AST.gif"/></p>
<p><ref>Fiugre 2: Sample Abstract Syntax Tree</ref></p>
<p>In this example _select only points to a single node. In more complex
expressions the pointer will point to an whole sub-tree.</p>
</s3>
</s2><anchor name="typecheck"/>
<s2 title="Type-check and Cast Expressions">
<p>In many cases we will need to typecast the top node in the expression
sub-tree to suit the expected result-type of the expression, or to typecast
child nodes to suit the allowed types for the various operators in the
expression. This is done by calling 'typeCheck()' on the root-node in the
XSL tree. Each SyntaxTree node is responsible for its own type checking
(ie. the <code>typeCheck()</code> method must be overridden). Let us say that
out pattern was:</p>
<p><code><xsl:value-of select="1+2.73"/></code></p>
<p><img src="typecast.gif" alt="typecast.gif"/></p>
<p><ref>Figure 3: XPath expression type conflict</ref></p>
<p>The number 1 is an integer, and the number 2.73 is a real number, so the
1 has to be promoted to a real. This is done ny inserting a new node between
the [1] and the [+]. This node will convert the 1 to a real number:</p>
<p><img src="cast_expression.gif" alt="cast_expression.gif"/></p>
<p><ref>Figure 4: Type casting</ref></p>
<p>The inserted node is an object of the class CastExpr. The SymbolTable
that was instanciated in (1) is used to determine what casts are needed for
the various operators and what return types the various expressions will
have.</p>
</s2><anchor name="compile"/>
<s2 title="Code generation">
<ul>
<li><link anchor="toplevelelem">Compiling top-level elements</link></li>
<li><link anchor="templatecode">Compiling template code</link></li>
<li><link anchor="instrfunc">Compiling XSL instructions and functions</link></li>
</ul>
<p>A general rule is that all classes that represent elements in the XSL
tree/document, i.e. classes that inherit from SyntaxTreeNode output
bytecode in the 'translate()' method.</p>
<anchor name="toplevelelem"/>
<s3 title="Compiling top-level elements">
<p>The bytecode that handles top-level elements must be generated before any
other code. The '<code>translate()</code>' method in these classes are mainly
called from these methods in the Stylesheet class:</p>
<source> private String compileBuildKeys(ClassGenerator classGen);
private String compileTopLevel(ClassGenerator classGen, Enumeration elements);
private void compileConstructor(ClassGenerator classGen, Output output);</source>
<p>These methods handle most top-level elements, such as global variables
and parameters, <code><xsl:output></code> and
<code><xsl:decimal-format></code> instructions.</p>
</s3><anchor name="templatecode"/>
<s3 title="Compiling template code">
<p>All XPath patterns in <code><xsl:apply-template></code> instructions
are converted into numeric values (known as the pattern's kernel 'type').
All templates with identical pattern kernel types are grouped together and
inserted into a table with its assigned type. (This table is found in the
Mode class. There will be one such table for each mode that is used in the
stylesheet). This table is used to build a big <code>switch()</code> statement
in the translet's <code>applyTemplates()</code> method. This method is initially
called with the root node of the input document.</p>
<p>The <code>applyTemplates()</code> method determines the node's type and passes
this type to the <code>switch()</code> statement to look up the matching
template.</p>
<p>There may be several templates that share the same pattern kernel type.
Here are a few examples of templates with patterns that all have the same
kernel type:</p>
<source> <xsl:template match="A/C">
<xsl:template match="A/B/C">
<xsl:template match="A | C"></source>
<p>All these templates will be grouped under the type for <code><C></code>
and will all get the same kernel type (the type for <code>"C"</code>). The last
template will be grouped both under <code>"C"</code> and <code>"A"</code>. If the
type identifier for <code>"C"</code> in this case is 8, all these templates will
be put under <code>case 8:</code> in <code>applyTemplates()</code>'s big
<code>switch()</code> statement. The Mode class will insert extra code to choose
which template code to invoke.</p>
</s3><anchor name="instrfunc"/>
<s3 title="Compiling XSL instructions and functions">
<p>The template code is generated by calling <code>translate()</code> on each
Template object in the abstract syntax tree. This call will be propagated
down the tree and every element will output the bytecodes necessary to
complete its task.</p>
<p>Each node will call 'translate()' on its children, and possibly on
objects representing the node's XPath expressions, before outputting its
own bytecode. In that way the correct sequence of instructions is generated.
Each one of the child nodes is responsible of creating code that leaves the
node's output value (if any) on the stack. The typical procedure for the
parent node is to create code that consumes these values off the stack and
then leave its own output on the stack for its parent.</p>
<p>The tree-structure of the stylesheet is in this way closely tied with
the stack-based JVM. The design does not offer any obvious way of extending
the compiler to output code for other VMs or processors.</p>
</s3>
</s2>
</s1>
1.1 xml-xalan/java/xdocs/sources/xsltc/xsltc_dom.xml
Index: xsltc_dom.xml
===================================================================
<?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="XSLTC Internal DOM">
<ul>
<li><link anchor="functionality">General functionlaity</link></li>
<li><link anchor="components">Components of the internal DOM</link></li>
<li><link anchor="structure">Internal structure</link></li>
<li><link anchor="navigation">Tree navigation</link></li>
<li><link anchor="namespaces">Namespaces</link></li>
<li><link anchor="w3c">W3C DOM2 navigation support</link></li>
<li><link anchor="adapter">The DOM adapter - DOMAdapter</link></li>
<li><link anchor="multiplexer">The DOM multiplexer - MultiDOM</link></li>
<li><link anchor="builder">The DOM builder - DOMImpl$DOMBuilder</link></li>
</ul>
<anchor name="functionality"/>
<s2 title="General functionality">
<p>The internal DOM gives the translet access to the XML document(s) it has
to transform. The interface to the internal DOM is specified in the DOM.java
class. This is the interface that the translet uses to access the DOM.
There is also an interface specified for DOM caches -- DOMCache.java</p>
</s2><anchor name="components"/>
<s2 title="Components of the internal DOM">
<p>This DOM interface is implemented by three classes:</p>
<ul>
<li><em>org.apache.xalan.xsltc.dom.DOMImpl</em><br/><br/>
This is the main DOM class. An instance of this class contains the nodes
of a <em>single</em> XML document.<br/>br/>
</li>
<li><em>org.apache.xalan.xsltc.dom.MultiDOM</em><br/><br/>
This class is best described as a DOM multiplexer. XSLTC was initially
designed to operate on a single XML document, and the initial DOM and
the DOM interface were designed and implemented without the
<code>document()</code> function in mind. This class will allow a translet
to access multiple DOMs through the original DOM interface.<br/><br/>
</li>
<li><em>org.apache.xalan.xsltc.dom.DOMAdapter</em><br/>br/>
The DOM adapter is a mediator between a DOMImpl or a MultiDOM object and
a single translet. A DOMAdapter object contains mappings and reverse
mappings between node types in the DOM(s) and node types in the translet.
This mediator is needed to allow several translets access to a single DOM.
<br/>br/>
</li>
<li><em>org.apache.xalan.xsltc.dom.DocumentCache</em><br/>br/>
A sample DOM cache (implementing DOMCache) that is used with our sample
transformation applications.
</li>
</ul>
<p><img src="DOMInterface.gif" alt="DOMInterface.gif"/></p>
<p><ref>Figure 1: Main components of the internal DOM</ref></p>
<p>The figure above shows how several translets can access one or more
internal DOM from a shared pool of cached DOMs. A translet can also access a
DOM tree outside of a cache. The Stylesheet class that represents the XSL
stylesheet to compile contains a flag that indicates if the translet uses the
<code>document()</code> function. The code compiled into the translet will act
accordingly and instanciate a MultiDOM object if needed (this code is compiled
in the compiler's <code>Stylesheet.compileTransform()</code> method).</p>
</s2><anchor name="structure"/>
<s2 title="Internal Structure">
<ul>
<li><link anchor="node-id">Node identification</link></li>
<li><link anchor="element-nodes">Element nodes</link></li>
<li><link anchor="attribute-nodes">Attribute nodes</link></li>
<li><link anchor="text-nodes">Text nodes</link></li>
<li><link anchor="comment-nodes">Comment nodes</link></li>
<li><link anchor="pi"></link>Processing instructions</li>
</ul>
<anchor name="node-id"/>
<s3 title="Node identifation">
<p>Each node in the DOM is represented by an integer. This integer is an
index into a series of arrays that describes the node. Most important is
the <code>_type[]</code> array, which holds the (DOM internal) node type. There
are some general node types that are described in the DOM.java interface:</p>
<source>
public final static int ROOT = 0;
public final static int TEXT = 1;
public final static int UNUSED = 2;
public final static int ELEMENT = 3;
public final static int ATTRIBUTE = 4;
public final static int PROCESSING_INSTRUCTION = 5;
public final static int COMMENT = 6;
public final static int NTYPES = 7;
</source>
<p>Element and attribute nodes will be assigned types based on their expanded
QNames. The <code>_type[]</code> array is used for this:</p>
<source>
int type = _type[node]; // get node type
</source>
<p>The node type can be used to look up the element/attribute name in the
element/attribute name array <code>_namesArray[]</code>:</p>
<source>
String name = _namesArray[type-NTYPES]; // get node element name
</source>
<p>The resulting string contains the full, expanded QName of the element or
attribute. Retrieving the namespace URI of an element/attribute is done in a
very similar fashion:</p>
<source>
int nstype = _namespace[type-NTYPES]; // get namespace type
String namespace = _nsNamesArray[nstype]; // get node namespace name
</source>
</s3><anchor name="element-nodes"/>
<s3 title="Element nodes">
<p>The contents of an element node (child nodes) can be identified using
the <code>_offsetOrChild[]</code> and <code>_nextSibling[]</code> arrays. The
<code>_offsetOrChild[]</code> array will give you the first child of an element
node:</p>
<source>
int child = _offsetOrChild[node]; // first child
child = _nextSibling[child]; // next child
</source>
<p>The last child will have a "<code>_nextSibling[]</code>" of 0 (zero).
This value is OK since the root node (the 0 node) will not be a child of
any element.</p>
</s3><anchor name="attribute-nodes"/>
<s3 title="Attribute nodes">
<p>The first attribute node of an element is found by a lookup in the
<code>_lengthOrAttr[]</code> array using the node index:</p>
<source>
int attribute = _offsetOrChild[node]; // first attribute
attribute = _nextSibling[attribute]; // next attribute
</source>
<p>The names of attributes are contained in the <code>_namesArray[]</code> just
like the names of element nodes. The value of attributes are store the same
way as text nodes:</p>
<source>
int offset = _offsetOrChild[attribute]; // offset into character array
int length = _lengthOrAttr[attribute]; // length of attribute value
String value = new String(_text, offset, length);
</source>
</s3><anchor name="text-nodes"/>
<s3 title="Text nodes">
<p>Text nodes are stored identically to attribute values. See the previous
section on <link anchor="attribute-nodes">attribute nodes</link>.</p>
</s3><anchor name="comment-nodes"/>
<s3 title="Comment nodes">
<p>The internal DOM does currently <em>not</em> contain comment nodes. Yes, I
am quite aware that the DOM has a type assigned to comment nodes, but comments
are still not inserted into the DOM.</p>
</s3><anchor name="pi"/>
<s3 title="Processing instructions">
<p>Processing instructions are handled as text nodes. These nodes are stored
identically to attribute values. See the previous section on
<link anchor="attribute-nodes">attribute nodes</link>.</p>
</s3></s2><anchor name="navigation"/>
<s2 title="Tree navigation">
<p>The DOM implementation contains a series of iterator that implement the
XPath axis. All these iterators implement the NodeIterator interface and
extend the NodeIteratorBase base class. These iterators do the job of
navigating the tree using the <code>_offsetOrChild[]</code>, <code>_nextSibling</code>
and <code>_parent[]</code> arrays. All iterators that handles XPath axis are
implemented as a private inner class of DOMImpl. The translet uses a handful
of methods to instanciate these iterators:</p>
<source>
public NodeIterator getIterator();
public NodeIterator getChildren(final int node);
public NodeIterator getTypedChildren(final int type);
public NodeIterator getAxisIterator(final int axis);
public NodeIterator getTypedAxisIterator(final int axis, final int type);
public NodeIterator getNthDescendant(int node, int n);
public NodeIterator getNamespaceAxisIterator(final int axis, final int ns);
public NodeIterator orderNodes(NodeIterator source, int node);
</source>
<p>There are a few iterators in addition to these, such as sorting/ordering
iterators and filtering iterators. These iterators are implemented in
separate classes and can be instanciated directly by the translet.</p>
</s2><anchor name="namespaces"/>
<s2 title="Namespaces">
<p>Namespace support was added to the internal DOM at a late stage, and the
design and implementation of the DOM bears a few scars because of this.
There is a separate <link idref="xsltc_namespace">design
document</link> that covers namespaces.</p>
</s2><anchor name="w3c"/>
<s2 title="W3C DOM2 navigation support">
<p>The DOM has a few methods that give basic W3C-type DOM navigation. These
methods are:</p>
<source>
public Node makeNode(int index);
public Node makeNode(NodeIterator iter);
public NodeList makeNodeList(int index);
public NodeList makeNodeList(NodeIterator iter);
</source>
<p>These methods return instances of inner classes of the DOM that implement
the W3C Node and NodeList interfaces.</p>
</s2><anchor name="adapter"/>
<s2 title="The DOM adapter - DOMAdapter">
<ul>
<li><link anchor="translet-dom">Translet/DOM type mapping</link></li>
<li><link anchor="whitespace">Whitespace text-node stripping</link></li>
<li><link anchor="method-mapping">Method mapping</link></li>
</ul>
<anchor name="translet-dom"/>
<s3 title="Translet/DOM type mapping">
<p>The DOMAdapter class performs the mappings between DOM and translet node
types, and vice versa. These mappings are necessary in order for the translet
to correctly identify an element/attribute in the DOM and for the DOM to
correctly identify the element/attribute type of a typed iterator requested
by the translet. Note that the DOMAdapter also maps translet namespace types
to DOM namespace types, and vice versa.</p>
<p>The DOMAdapter class has four global tables that hold the translet/DOM
type and namespace-type mappings. If the DOM knows an element as type
19, the DOMAdapter will translate this to some other integer using the
<code>_mapping[]</code> array:</p>
<source>
int domType = _mapping[transletType];
</source>
<p>This action will be performed when the DOM asks what type a specific node
is. The reverse is done then the translet wants an iterator for a specific
node type. The DOMAdapter must translate the translet-type to the type used
internally in the DOM by looking up the <code>_reverse[]</code> array:</p>
<source>
int transletType = _mapping[domType];
</source>
<p>There are two additional mapping tables: <code>_NSmapping[]</code> and
<code>_NSreverse[]</code> that do the same for namespace types.</p>
</s3><anchor name="whitespace"/>
<s3 title="Whitespace text-node stripping">
<p>The DOMAdapter class has the additional function of stripping whitespace
nodes in the DOM. This functionality had to be put in the DOMAdapter, as
different translets will have different preferences for node stripping.</p>
</s3><anchor name="method-mapping"/>
<s3 title="Method mapping">
<p>The DOMAdapter class implements the same <code>DOM</code> interface as the
DOMImpl class. A DOMAdapter object will look like a DOMImpl tree, but the
translet can access it directly without being concerned with type mapping
and whitespace stripping. The <code>getTypedChildren()</code> demonstrates very
well how this is done:</p>
<source>
public NodeIterator getTypedChildren(int type) {
// Get the DOM type for the requested typed iterator
final int domType = _reverse[type];
// Now get the typed child iterator from the DOMImpl object
NodeIterator iterator = _domImpl.getTypedChildren(domType);
// Wrap the iterator in a WS stripping iterator if child-nodes are text nodes
if ((domType == DOM.TEXT) && (_filter != null))
iterator = _domImpl.strippingIterator(iterator,_mapping,_filter);
return(iterator);
}
</source>
</s3></s2><anchor name="multiplexer"/>
<s2 title="The DOM multiplexer - MultiDOM">
<p>The DOM multiplexer class is only used when the compiled stylesheet uses
the <code>document()</code> function. An instance of the MultiDOM class also
implements the DOM interface, so that it can be accessed in the same way
as a DOMAdapter object.</p>
<p>A node in the DOM is identified by an integer. The first 8 bits of this
integer are used to identify the DOM in which the node belongs, while the
lower 24 bits are used to identify the node within the DOM:</p>
<table>
<tr>
<td>31-24</td>
<td>23-16</td>
<td>16-8</td>
<td>7-0</td>
</tr>
<tr>
<td>DOM id</td>
<td colspan="3">node id</td>
</tr>
</table>
<p>The DOM multiplexer has an array of DOMAdapter objects. The topmost 8
bits of the identifier is used to find the correct DOM from the array. Then
the lower 24 bits are used in calls to methods in the DOMAdapter object:</p>
<source>
public int getParent(int node) {
return _adapters[node>>>24].getParent(node & 0x00ffffff) | node & 0xff000000;
}
</source>
<p>Note that the node identifier returned by this method has the same upper 8
bits as the input node. This is why we <code>OR</code> the result from
<code>DOMAdapter.getParent()</code> with the top 8 bits of the input node.</p>
</s2><anchor name="builder"/>
<s2 title="The DOM builder - DOMImpl$DOMBuilder">
<ul>
<li><link anchor="startelement">startElement()</link></li>
<li><link anchor="endelement">endElement()</link></li>
<li><link anchor="startprefixmapping">startPrefixMapping()</link></li>
<li><link anchor="endprefixmapping">endPrefixMapping()</link></li>
<li><link anchor="characters">characters()</link></li>
<li><link anchor="startdocument">startDocument()</link></li>
<li><link anchor="enddocument">endDocument()</link></li>
</ul>
<p>The DOM builder is an inner class of the DOM implementation. The builder
implements the SAX2 <code>ContentHandler</code> interface and populates the DOM
by receiving SAX2 events from a SAX2 parser (presently xerces). An instance
of the DOM builder class can be retrieved from <code>DOMImpl.getBuilder()</code>
method, and this handler can be set as an XMLReader's content handler:</p>
<source>
final SAXParserFactory factory = SAXParserFactory.newInstance();
final SAXParser parser = factory.newSAXParser();
final XMLReader reader = parser.getXMLReader();
final DOMImpl dom = new DOMImpl();
reader.setContentHandler(dom.getBuilder());
</source>
<p>The DOM builder will start to populate the DOM once the XML parser starts
generating SAX2 events:</p>
<anchor name="startelement"/>
<s3 title="startElement()">
<p>This method can be called in one of two ways; either with the expanded
QName (the element's separate uri and local name are supplied) or as a
normal QName (one String on the format prefix:local-name). The DOM stores
elements as expanded QNames so it needs to know the element's namespace URI.
Since the URI is not supplied with this call, we have to keep track of
namespace prefix/uri mappings while we're building the DOM. See
<code><link anchor="startprefixmapping">startPrefixMapping()</link></code> below for details on
namespace handling.</p>
<p>The <code>startElement()</code> inserts the element as a child of the current
parent element, creates attribute nodes for all attributes in the supplied
"<code>Attributes</code>" attribute list (by a series of calls to
<code>makeAttributeNode()</code>), and finally creates the actual element node
(by calling <code>internElement()</code>, which inserts a new entry in the
<code>_type[]</code> array).</p>
</s3><anchor name="endelement"/>
<s3 title="endElement()">
<p>This method does some cleanup after the <code>startElement()</code> method,
such as revering <code>xml:space</code> settings and linking the element's
child nodes.</p>
</s3><anchor name="startprefixmapping"/>
<s3 title="startPrefixMapping()">
<p>This method is called for each namespace declaration in the source
document. The parser should call this method before the prefix is referenced
in a QName that is passed to the <code>startElement()</code> call. Namespace
prefix/uri mappings are stored in a Hashtable structure. Namespace prefixes
are used as the keys in the Hashtable, and each key maps to a Stack that
contains the various URIs that the prefix maps to. The URI on top of the
stack is the URI that the prefix currently maps to.</p>
<p><img src="namespace_stack.gif" alt="namespace_stack.gif"/></p>
<p><ref>Figure 2: Namespace handling in the DOM builder</ref></p>
<p>Each call to <code>startPrefixMapping()</code> results in a lookup in the
Hashtable (using the prefix), and a <code>push()</code> of the URI onto the
Stack that the prefix maps to.</p>
</s3><anchor name="endprefixmapping"/>
<s3 title="endPrefixMapping()">
<p>A namespace prefix/uri mapping is closed by locating the Stack for the
prefix, and then <code>pop()</code>'ing the topmost URI off this Stack.</p>
</s3><anchor name="characters"/>
<s3 title="characters()">
<p>Text nodes are stored as simple character sequences in the character array
<code>_text[]</code>. The start and lenght of a node's text can be determined by
using the node index to look up <code>_offsetOrChild[]</code> and
<code>_lengthOrAttribute[]</code>.</p>
<p>We want to re-use character sequences if two or more text nodes have
identical content. This can be achieved by having two different text node
indexes map to the same character sequence. The <code>maybeReuseText()</code>
method is always called before a new character string is stored in the
<code>_text[]</code> array. This method will locate the offset of an existing
instance of a character sequence.</p>
</s3><anchor name="startdocument"/>
<s3 title="startDocument()">
<p>This method initialises a bunch of data structures that are used by the
builder. It also pushes the default namespace on the namespace stack (so that
the "" prefix maps to the <code>null</code> namespace).</p>
</s3><anchor name="enddocument"/>
<s3 title="endDocument()">
<p>This method builds the <code>_namesArray[]</code>, <code>_namespace[]</code>
and <code>_nsNamesArray[]</code> structures from temporary datastructures used
in the DOM builder.</p>
</s3>
</s2>
</s1>
1.1 xml-xalan/java/xdocs/sources/xsltc/xsltc_namespace.xml
Index: xsltc_namespace.xml
===================================================================
<?xml version="1.0" standalone="no"?>
<!--
* 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/>.
-->
<!DOCTYPE s1 SYSTEM "../../style/dtd/document.dtd">
<s1 title="XSLTC and Namespaces">
<ul>
<li><link anchor="functionality">Functionality</link></li>
<li><link anchor="overview">Namespace overview</link></li>
<li><link anchor="NSA">The DOM & namespaces</link></li>
<li><link anchor="NSB">Namespaces in the XSL stylesheet</link></li>
<li><link anchor="NSC">Namespaces in the output document</link></li>
</ul>
<anchor name="functionality"/>
<s2 title="Functionality">
<p>Namespaces are used when an XML documents has elements have the same
name, but are from different contexts, and thus have different meanings
and interpretations. For instance, a <code><TITLE></code> element can
be a HTML title element in one part of the XML document, while it in other
parts of the document the <code><TITLE></code> element is used for
encapsulating the title of a play or a book. This sort of confusion is
very common when reading XML source from multiple documents, but can also
occur within a single document.</p>
<p>Namespaces have three very important properties: a name, a prefix (an
alias for its name) and a scope. Namespaces are declared as attributes of
almost any node in an XML document. The declaration looks like this:</p>
<source>
<element xmlns:prefix="http://some.site/spec">....</element>
</source>
<p>The <code>"xmlns"</code> tells that this is a namespace declaration. The
scope of the namespace declaration is the element in which it is defined
and all the children of that element.The prefix is the local alias we use
for referencing the namespace, and the URL (it can be anything, really) is
the name/definition of the namespace. Note that even though the namespace
definition is normally an URL, it does not have to point to anything. It
is recommended that it points to a page that describes the elements in the
namespace, but it does not have to. The prefix can be just about anything
- or nothing (in which case it is the default namespace). Any prefix,
including the empty prefix for the default namespace, can be redefined to
refer to a different namespace at any time in an XML document. This is
more likely to happen to the default namespace than any other prefix. Here
is an example of this:</p>
<anchor name="xml_sample_1"/>
<source>
<?xml version="1.0"?>
<employees xmlns:postal="http://postal.ie/spec-1.0"
xmlns:email="http://www.w3c.org/some-spec-3.2">
<employee>
<name>Bob Worker</name>
<postal:address>
<postal:street>Nassau Street</postal:street>
<postal:city>Dublin 3</postal:city>
<postal:country>Ireland</postal:country>
</postal:address>
<email:address>bob.worker@hisjob.ie</email:address>
</employee>
</employees>
</source>
<p>This short document has two namespace declarations, one with the prefix
<code>"postal"</code> and another with the prefix <code>"email"</code>. The
prefixes are used to distinguish between elements for e-mail addresses and
regular postal addresses. In addition to these two namespaces there is also
an initial (unnamed) default namespace being used for the
<code><name></code> and <code><employee></code> tags. The scope of the
default namespace is in this case the whole document, while the scope of
the other two declared namespaces is the <code><employees></code>
element and its children.</p>
<p>By changing the default namespace we could have made the document a
little bit simpler and more readable:</p>
<anchor name="xml_sample_2"/>
<source>
<?xml version="1.0"?>
<employees xmlns:email="http://www.w3c.org/some-spec-3.2">
<employee>
<name>Bob Worker</name>
<address xmlns="http://postal.ie/spec-1.0">
<street>Nassau Street</street>
<city>Dublin 3</city>
<country>Ireland</country>
</address>
<email:address>bob.worker@hisjob.ie</email:address>
</employee>
</employees>
</source>
<p>The default namespace is redefined for the <code><address></code> node
and its children, so there is no need to specify the street as
<code><postal:street></code> - just plain <code><street></code> is
sufficient. Note that this also applies to the <code><address></code>
where the namespace is first defined. This is in effect a redefinition of
the default namespace.</p>
</s2><anchor name="overview"/>
<s2 title="Namespace overview">
<p>Namespaces will have to be handled in three separate parts of the XSLT
compiler:</p>
<anchor name="all_namespaces"/>
<p><img src="all_namespaces.gif" alt="all_namespaces.gif"/></p>
<p><ref>Figure 1: Namespace handlers in the XSLTC</ref></p>
<p>The most obvious is the namespaces in the source XML document
(marked <link anchor="NSA">"NS A"</link> in figure 1). These namespaces will be
handled by our DOM implementation class. The source XSL stylesheet also
has its own set of namespaces (<link idref="NSB">"NS B"</link>) - one of which
is the XSL namespace. These namespaces will be handled at run-time and
whatever information that is needed to process there should be compiled
into the translet. There is also a set of namespaces that will be used in
the resulting document (<link idref="NSC">"NS C"</link>). This is an
intersection of the first two. The output document should not contain any
more namespace declarations than necessary.</p>
</s2><anchor name="NSA"/>
<s2 title="The DOM & namespaces">
<ul>
<li><link anchor="dom-namespace">DOM node types and namespace types</link></li>
<li><link anchor="assign">Assigning namespace types to DOM nodes</link></li>
</ul>
<anchor name="dom-namespace"/>
<s3 title="DOM node types and namespace types">
<p>Refer to the XSLTC <link idref="xsltc_runtime">runtime
environment design</link> document for a description of node types before
proceeding. In short, each node in the our DOM implementation is
represented by a simple integer. By using this integer as an index into an
array called <code>_type[]</code> we can find the type of the node.</p>
<p>The type of the node is an integer representing the type of element the
node is. All elements <code><bob></code> will be given the same type,
all text nodes will be given the same type, and so on. By using the node
type as an index an array called <code>_namesArray[]</code> we can find the
name of the element type - in this case "bob". This code fragment shows
how you can, with our current implementation, find the name of a node:</p>
<source>
int node = iterator.getNext(); // get next node
int type = _type[node]; // get node type
String name = _namesArray[type]; // get node name
</source>
<p>We want to keep the one-type-per-node arrangement, since that lets us
produce fairly efficient code. One type in the DOM maps to one type in
the compiled translet. What we could do to represent the namespace for
each node in the DOM is to add a <code>_namespaceType[]</code> array that holds
namespace types. Each node type maps to a namespace type, and each
namespace type maps to a namespace name (and a prefix with a limited
scope):</p>
<anchor name="type_mappings"/>
<p><img src="type_mappings.gif" alt="type_mappings.gif"/></p>
<p><ref>Figure 2: Mapping between node types/names, namespace types/names</ref></p>
<p>This code fragment shows how we could get the namespace name for a node:</p>
<source>
int node = iterator.getNext(); // get next node
int type = _type[node]; // get node type
int nstype = _namespace[type]; // get namespace type
String name = _namesArray[type]; // get node element name
String namespace = _nsNamesArray[nstype]; // get node namespace name
</source>
<p>Note that namespace prefixes are not included here. Namespace prefixes
are local to the XML document and will be expanded to the full namespace
names when the nodes are put into the DOM. This, however, is not a trivial
matter.</p>
</s3><anchor name="assign"/>
<s3 title="Assigning namespace types to DOM nodes">
<p>We cannot simply have a single namespace prefix array similar to the
<code>_namespaceArray[]</code> array for mapping a namespace type to a single
prefix. This because prefixes can refer to different namespaces depending
on where in the document the prefixes are being used. In our last example's
<link idref="xml_sample_2">XML fragment</link> the empty prefix <code>""</code>
initially referred to the default namespace (the one with no name - just
like a Clint Eastwood character). Later on in the document the empty
prefix is changed to refer to a namespace called
<code>"http://postal.ie/spec-1.0"</code>.</p>
<p>Namespace prefixes are only relevant at the time when the XML document
is parsed and the DOM is built. Once we have the DOM completed we only need
a table that maps each node type to a namespace type, and another array of
all the names of the different namespaces. So what we want to end up with
is something like this:</p>
<p><img src="dom_namespace1.gif" alt="dom_namespace1.gif"/></p>
<p><ref>Figure 3: Each namespace references in the DOM gets one entry</ref></p>
<p>The namespace table has one entry for each namespace, nomatter how many
prefixes were used ro reference this namespace in the DOM. To build this
array we need a temporary data structure used by the DOM builder. This
structure is a hashtable - where the various prefixes are used for the
hash values. The contents of each entry in the table will be a small stack
where previous meanings of each prefix will be stored:</p>
<p><img src="dom_namespace2.gif" alt="dom_namespace2.gif"/></p>
<p><ref>Figure 4: Temporary data structure used by the DOM builder</ref></p>
<p>When the first node is encountered we define a new namespace
<code>"foo"</code> and assign this namespace type/index 1 (the default
namespace <code>""</code> has index 0). At the same time we use the prefix
<code>"A"</code> for a lookup in the hashtable. This gives us
an integer stack used for the prefix <code>"A"</code>. We push the namespace
type 1 on this stack. From now on, until <code>"A"</code> is pop'ed off this
stack, the prefix <code>"A"</code> will map to namespace type 1, which
represents the namespace URI <code>"foo"</code>.</p>
<p>We then encounter the next node with a new namespace definition with
the same namespace prefix, we create a new namespace <code>"bar"</code> and
we put that in the namespace table under type 2. Again we use the prefix
<code>"A"</code> as an entry into the namespace prefix table and we get the
same integer stack. We now push namespace type 2 on the stack, so that
namespace prefix <code>"A"</code> maps to namespace URI <code>"bar"</code>. When
we have traversed this node's children we need to pop the integer off the
stack, so when we're back at the first node the prefix <code>"A"</code> again
will point to namespace type 0, which maps to <code>"foo"</code>. To keep
track of what nodes had what namespace declarations, we use a namespace
declaration stack:</p>
<p><img src="dom_namespace3.gif" alt="dom_namespace3.gif"/></p>
<p><ref>Figure 5: Namespace declaration stack</ref></p>
<p>Every namespace declaration is pushed on the namespace declaration
stack. This stack holds the node index for where the namespace was
declared, and a reference to the prefix stack for this declaration.
The <code>endElement()</code> method of the DOMBuilder class will need to
remove namespace declaration for the node that is closed. This is done
by first checking the namespace declaration stack for any namespaces
declared by this node. If any declarations are found these are un-declared
by poping the namespace prefixes off the respective prefix stack(s), and
then poping the entry/entries for this node off the namespace declaration
stack.</p>
<p>The <code>endDocument()</code> method will build an array that contains
all namespaces used in the source XML document - <code>_nsNamesArray[]</code>
- which holds the URIs of all refered namespaces. This method also builds
an array that maps all DOM node types to namespace types. This two arrays
are accessed through two new methods in the DOM interface:</p>
<source>
public String getNamespaceName(int node);
public int getNamespaceType(int node);
</source>
</s3></s2><anchor name="NSB"/>
<s2 title="Namespaces in the XSL stylesheet">
<ul>
<li><link anchor="store-access">Storing and accessing namespace information</link></li>
<li><link anchor="mapdom-stylesheet">Mapping DOM namespaces to stylesheet namespaces</link></li>
<li><link anchor="wildcards">Wildcards and namespaces</link></li>
</ul>
<anchor name="store-access"/>
<s3 title="Storing and accessing namespace information">
<p>The SymbolTable class has three datastructures that are used to hold
namespace information:</p>
<ul>
<li>
First there is the <code>_namespaces[]</code> Hashtable that maps the names
of in-scope namespace to their respective prefixes. Each key in the
Hashtable object has a stack. A new prefix is pushed on the stack for
each new declaration of a namespace.
</li>
<li>
Then there is the <code>_prefixes[]</code> Hashtable. This has the reverse
function of the <code>_namespaces[]</code> Hashtable - it maps from
prefixes to namespaces.
</li>
<li>
There is also a hashtable that is used for implementing the
<code><xsl:namespace-alias></code> element. The keys in this
hashtable is taken from the <code>stylesheet-prefix</code> attribute of
this element, and the resulting prefix (from the <code>result-prefix</code>
attribute) is used as the value for each key.
</li>
</ul>
<p>The SymbolTable class offers 4 methods for accessing these data
structures:</p>
<source>
public void pushNamespace(String prefix, String uri);
public void popNamespace(String prefix);
public String lookupPrefix(String uri);
public String lookupNamespace(String prefix);
</source>
<p>These methods are wrapped by two methods in the Parser class (a Parser
object alwas has a SymbolTable object):</p>
<source>
// This method pushes all namespaces declared within a single element
public void pushNamespaces(ElementEx element);
// This method pops all namespaces declared within a single element
public void popNamespaces(ElementEx element);
</source>
<p>The translet class has, just like the DOM, a <code>namesArray[]</code>
structure for holding the expanded QNames of all accessed elements. The
compiled translet fills this array in its constructor. When the translet
has built the DOM (a DOMImpl object), it passes the DOM to the a DOM
adapter (a DOMAdapter object) together with the names array. The DOM
adapter then maps the translet's types to the DOM's types.</p>
</s3><anchor name="mapdom-stylesheet"/>
<s3 title="Mapping DOM namespaces and stylesheet namespaces">
<p>Each entry in the DOM's <code>_namesArray[]</code> is expanded to contain
the full QName, so that instead of containing <code>prefix:localname</code> it
will now contain <code>namespace-uri:localname</code>. In this way the expanded
QName in the translet will match the exanded QName in the DOM. This assures
matches on full QNames, but does not do much for <code>match="A:*"</code> type
XPath patterns. This is where our main challenge lies.</p>
</s3><anchor name="wildcards"/>
<s3 title="Wildcards and namespaces">
<p>The original implementation of the XSLTC runtime environment would
only allow matches on "<code>*</code>" and "<code>@*</code>" patterns. This was
achieved by mapping all elements that could not be mapped to a translet
type to 3 (DOM.ELEMENT type), and similarly all unknown attributes to
type 4 (DOM.ATTRIBUTE type). The main <code>switch()</code> statement in
<code>applyTemplates()</code> would then have a separate "<code>case()</code>"
for each of these. (Under each <code>case()</code> you might have to check
for the node's parents in case you were matching on "<code>path/*</code>"-type
patterns.) This figure shows how that was done:</p>
<anchor name="match_namespace1"/>
<p><img src="match_namespace1.gif" alt="match_namespace1.gif"/></p>
<p><ref>Figure 6: Previous pattern matching</ref></p>
<p>The "Node test" box here represents the "<code>switch()</code>" statement.
The "Node parent test" box represent each "<code>case:</code>" for that
<code>switch()</code> statement. There is one <code>case:</code> for each know
translet node type. For each node type we have to check for any parent
patterns - for instance, for the pattern "<code>/foo/bar/baz</code>", we will
get a match with <code>case "baz"</code>, and we have to check that the parent
node is "<code>bar</code>" and that the grandparent is "<code>foo</code>" before
we can say that we have a hit. The "Element parent test" is the test that
is done all DOM nodes that do not directly match any translet types. This
is the test for "<code>*</code>" or "<code>foo/*</code>". Similarly we have a
"<code>case:</code>" for match on attributes ("<code>@*</code>").</p>
<p>What we now want to achieve is to insert a check for patterns on the
format "<code>ns:*</code>", "<code>foo/ns:*</code>" or "<code>ns:@*</code>", which
this figure illustrates:</p>
<anchor name="match_namespace2"/>
<p><img src="match_namespace2.gif" alt="match_namespace2.gif"/></p>
<p><ref>Figure 7: Pattern matching with namespace tests</ref></p>
<p>Each node in the DOM needs a namespace type as well as the QName type.
With this type we can match wildcard rules to any specific namespace.
So after any checks have been done on the whole QName of a node (the type),
we can match on the namespace type of the node. The main dispatch
<code>switch()</code> in <code>applyTemplates()</code> must be changed from this:</p>
<source>
public void applyTemplates(DOM dom, NodeIterator iterator,
TransletOutputHandler handler) {
// Get next node from iterator
while ((node = iterator.next()) != END) {
// Get internal node type
final int type = DOM.getType(node);
switch(type) {
case DOM.ROOT: // Match on "/" pattern
handleRootNode();
break;
case DOM.TEXT: // Handle text nodes
handleText();
break;
case DOM.ELEMENT: // Match on "*" pattern
handleWildcardElement();
break;
case DOM.ATTRIBUTE: // Handle on "@*" pattern
handleWildcardElement();
break;
case nodeType1: // Handle 1st known element type
compiledCodeForType1();
break;
:
:
:
case nodeTypeN: // Handle nth known element type
compiledCodeForTypeN();
break;
default:
NodeIterator newIterator = DOM.getChildren(node);
applyTemplates(DOM, newIterator, handler);
break;
}
}
return;
}
</source>
<p>To something like this:</p>
<source>
public void applyTemplates(DOM dom, NodeIterator iterator,
TransletOutputHandler handler) {
// Get next node from iterator
while ((node = iterator.next()) != END) {
// First run check on node type
final int type = DOM.getType(node);
switch(type) {
case DOM.ROOT: // Match on "/" pattern
handleRootNode();
continue;
case DOM.TEXT: // Handle text nodes
handleText();
continue;
case DOM.ELEMENT: // Not handled here!!!
break;
case DOM.ATTRIBUTE: // Not handled here!!!
break;
case nodeType1: // Handle 1st known element type
if (compiledCodeForType1() == match) continue;
break;
:
:
:
case nodeTypeN: // Handle nth known element type
if (compiledCodeForTypeN() == match) continue;
break;
default:
break;
}
// Then run check on namespace type
final int namespace = DOM.getNamespace(type);
switch(namespace) {
case 0: // Handle nodes matching 1st known namespace
if (handleThisNamespace() == match) continue;
break;
case 1: // Handle nodes matching 2nd known namespace
if (handleOtherNamespace() == match) continue;
break;
}
// Finally check on element/attribute wildcard
if (type == DOM.ELEMENT) {
if (handleWildcardElement() == match)
continue;
else {
// The default action for elements
NodeIterator newIterator = DOM.getChildren(node);
applyTemplates(DOM, newIterator, handler);
}
}
else if (type == DOM.ATTRIBUTE) {
handleWildcardAttribute();
continue;
}
}
}
</source>
<p>First note that the default action (iterate on children) does not hold for
attributes, since attribute nodes do not have children. Then note that the way
the three levels of tests are ordered is consistent with the way patterns
should be prioritised:</p>
<ul>
<li><em>Match on element/attribute types:</em></li>
<ul>
<li><code>match="/"</code> - match on the root node</li>
<li><code>match="B"</code> - match on any B element</li>
<li><code>match="A/B"</code> - match on B elements with A parent</li>
<li><code>match="A | B"</code> - match on B or A element</li>
<li><code>match="foo:B"</code> - match on B element within "foo" namespace</li>
</ul>
<li><em>Match on namespace:</em></li>
<ul>
<li><code>match="foo:*"</code> - match on any element within "foo" namespace</li>
<li><code>match="foo:@*"</code> - match on any attribute within "foo" namespace</li>
<li><code>match="A/foo:*"</code> - match on any element within "foo" namespace with A parent</li>
<li><code>match="A/foo:@*"</code> - match on any attribute within "foo" namespace with A parent</li>
</ul>
<li><em>Match on wildcard:</em> </li>
<ul>
<li><code>match="*"</code> - match on any element</li>
<li><code>match="@*"</code> - match on any attribute</li>
<li><code>match="A/*"</code> - match on any element with A parent</li>
<li><code>match="A/@*"</code> - match on any attribute with A parent</li>
</ul>
</ul>
</s3></s2><anchor name="NSC"/>
<s2 title="Namespaces in the output document">
<p>These are the categories of namespaces that end up in the output
document:</p>
<ul>
<li>
Namespaces used in literal elements/attributes in the stylesheet. These
namespaces should be declared <em>once</em> before use in the output
document. These elements are copied to the output document independent
of namespaces in the input XML document. However, the namespaces can
be declared using the same prefix, such that a namespace used by a
literal result element can overshadow a namespace from the DOM.
</li>
<li>
Namespaces from elements in the stylesheet that match elements in the
DOM. No namespaces from the DOM should be copied to the output document
unless they are actually referenced in the stylesheet. No namespaces
from the stylesheet should be copied to the output document unless the
elements in which they are references match elements in the DOM.
</li>
</ul>
<anchor name="output_namespaces1"/>
<p><img src="output_namespaces1.gif" alt="output_namespaces1.gif"/></p>
<p><ref>Figure 8: Namespace declaration in the output document</ref></p>
<p>Any literal element that ends up in the output document must declare all
namespaces that were declared in the <code><xsl:stylesheet<</code>
element. Exceptions are namespaces that are listed in this element's
<code>exclude-result-prefixes</code> or <code>extension-element-prefixes</code>
attributes. These namespaces should only be declared if they are referenced
in the output.</p>
<p>Literal elements should only declare namespaces when necessary. A
literal element should only declare a namespace in the case where it
references a namespace using prefix that is not in scope for this
namespace. The output handler will take care of this problem. All namespace
declarations are put in the output document using the output handler's
<code>declarenamespace()</code> method. This method will monitor all namespace
declarations and make sure that no unnecessary declarations are output.
The datastructures used for this are similar to those used to track
namespaces in the XSL stylesheet:</p>
<anchor name="output_namespaces2"/>
<p><img src="output_namespaces2.gif" alt="output_namespaces2.gif"/></p>
<p><ref>Figure 9: Handling Namespace declarations in the output document</ref></p>
</s2>
</s1>
1.1 xml-xalan/java/xdocs/sources/xsltc/xsltc_runtime.xml
Index: xsltc_runtime.xml
===================================================================
<?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="XSLTC runtime environment">
<ul>
<li><link anchor="overview">Runtime overview</link></li>
<li><link anchor="translet">The compiled translet</link></li>
<li><link anchor="types">External/internal type mapping</link></li>
<li><link anchor="mainloop">Main program loop</link></li>
</ul>
<anchor name="overview"/>
<s2 title="Runtime overview">
<p>The actual transformation of the input XML document is initiated by
one of these classes:</p>
<ul>
<li>
<code>com.sun.xslt.runtime.DefaultRun</code> (runs in a terminal)
</li>
<li>
<code>com.sun.xslt.demo.applet.TransformApplet</code> (runs in an applet)
</li>
<li>
<code>com.sun.xslt.demo.servlet.Translate</code> (runs in a servlet)
</li>
</ul>
<p>Any one of these classes will have to go through the folloing steps in
order to initiate a transformation:</p>
<ul>
<li>
Instanciate the translet object. The name of the translet (ie. class)
to use is passed to us as a string. We use this string as a parameter
to the static method <code>Class.forName(String name)</code> to get a
reference to a translet object.
</li>
<li>
Instanciate a <code>com.sun.xsl.parser.Parser</code> object to parse the
input XML file, and instanciate a DOM (we have our own DOM
implementation especially designed for XSLTC) where we store the
input document.
</li>
<li>
Pass any parameters to the translet (currently only possible when
running the transformation in a terminal using DefaultRun)
</li>
<li>
Instanciate a handler for the result document. This handler must be
extend the <code>TransletOutputHandler</code> class.
</li>
<li>
Invoke the <code>transform()</code> method on the translet, passing the
instanciated DOM and the output handler as parameters.
</li>
</ul>
</s2><anchor name="translet"/>
<s2 title="The compiled translet">
<p>A translet is always a subclass of <code>AbstractTranslet</code>. As well
as having access to the public/protected methods in this class, the
translet is compiled with these methods:</p>
<p><code>public void transform(DOM, NodeIterator, TransletOutputHandler);</code></p>
<p>This method is passed a <code>DOMImpl</code> object. Depending on whether
the stylesheet had any calls to the <code>document()</code> function this
method will either generate a <code>DOMAdapter</code> object (when only one
XML document is used as input) or a <code>MultiDOM</code> object (when there
are more than one XML input documents). This DOM object is passed on to
the <code>topLevel()</code> method.</p>
<p>When the <code>topLevel()</code> method returns we initiate the output
document by calling <code>startDocument()</code> on the supplied output
handler object. We then call <code>applyTemplates()</code> to get the actual
output contents, before we close the output document by calling
<code>endDocument()</code> on the output handler.</p>
<p><code>public void topLevel(DOM, NodeIterator, TransletOutputHandler);</code></p>
<p>This method handles all of these top-level elements:</p>
<ul>
<li><code><xsl:output></code></li>
<li><code><xsl:decimal-format></code></li>
<li><code><xsl:key></code></li>
<li><code><xsl:param></code> (for global parameters)</li>
<li><code><xsl:variable></code> (for global variables)</li>
</ul>
<p><code>public void applyTemplates(DOM, NodeIterator, TransletOutputHandler);</code></p>
<p>This is the method that produces the actual output. Its central element
is a big <code>switch()</code> statement that is used to choose the available
templates for the various node in the input document. See the chapter
<link anchor="mainloop">Main Program Loop</link> for details on this method.</p>
<p><code>public void <init> ();</code></p>
<anchor name="namesarray"/>
<p>The translet's constructor initializes a table
of all the elements we want to search for in the XML input document.
This table is called the <code>namesArray</code> and it is passed to the DOM
holding the input XML document.</p>
<p>The constructor also initializes any <code>DecimalFormatSymbol</code>
objects that are used to format numbers before passing them to the
output handler.</p>
<p><code>public boolean stripSpace(int nodeType);</code></p>
<p>This method is only present if any <code><xsl:strip-space></code> or
<code><xsl:preserve-space></code> elements are present in the stylesheet.
If that is the case, the translet implements the
<code>StripWhitespaceFilter</code> interface by containing this method.</p>
</s2><anchor name="types"/>
<s2 title="External/internal type mapping">
<anchor name="external-types"/>
<p>This is the very core of XSL transformations: <em>Read carefully!!!</em></p>
<p>Every node in the input XML document(s) is assigned a type by the
DOM builder class. This type is an integer value which represents the
element, so that for instance all <code><bob></code> elements in the
input document will be given type <ref>7</ref> and can be referred to by using
that integer. These types can be used for lookups in the
<link anchor="namesarray">namesArray</link> table to get the actual
element name (in this case "bob"). These types are referred to as
<em>external types</em> or <em>DOM types</em>, as they are types known only
to the DOM and the DOM builder.</p>
<anchor name="internal-types"/>
<p>Similarly the translet assignes types to all element and attribute names
that are referenced in the stylesheet. These types are referred to as
<em>internal types</em> or <em>translet types</em>.</p>
<p>It is not very probable that there will be a one-to-one mapping between
internal and external types. There will most often be elements in the DOM
(ie. the input document) that are not mentioned in the stylesheet, and
there could be elements in the stylesheet that do not match any elements
in the DOM. Here is an example:</p>
<source>
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="blahblahblah">
<xsl:template match="/">
<xsl:for-each select="//B">
<xsl:apply-templates select="." />
</xsl:for-each>
<xsl:for-each select="C">
<xsl:apply-templates select="." />
</xsl:for-each>
<xsl:for-each select="A/B">
<xsl:apply-templates select="." />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
</source>
<p>In this stylesheet we are looking for elements <code><B></code>,
<code><C></code> and <code><A></code>. For this example we can assume
that these element types will be assigned the values 0, 1 and 2. Now, lets
say we are transforming this XML document:</p>
<source>
<?xml version="1.0"?>
<A>
The crocodile cried:
<F>foo</F>
<B>bar</B>
<B>baz</B>
</A>
</source>
<p>This XML document has the elements <code><A></code>,
<code><B></code> and <code><F></code>, which we assume are assigned the
types 7, 8 and 9 respectively (the numbers below that are assigned for
specific element types, such as the root node, text nodes, etc.). This
causes a mismatch between the type used for <code><B></code> in the
translet and the type used for <code><B></code> in the DOM. Th
DOMAdapter class (which mediates between the DOM and the translet) has been
given two tables for convertint between the two types; <code>mapping</code> for
mapping from internal to external types, and <code>reverseMapping</code> for
the other way around.</p>
<p>The translet contains a <code>String[]</code> array called
<code>namesArray</code>. This array will contain all the element and attribute
names that were referenced in the stylesheet. In our example, this array
would contain these string (in this specific order): "B",
"C" and "A". This array is passed as one of the
parameters to the DOM adapter constructor (the other adapter is the DOM
itself). The DOM adapter passes this table on to the DOM. The DOM has
a hashtable that maps known element names to external types. The DOM goes
through the <code>namesArray</code> from the DOM sequentially, looks up each
name in the hashtable, and is then able to map the internal type to an
external type. The result is then passed back to the DOM adapter.</p>
<p>The reverse is done for external types. External types that are not
interesting for the translet (such as the type for <code><F></code>
elements in the example above) are mapped to a generic <code>"ELEMENT"</code>
type 3, and are more or less ignored by the translet.</p>
<p>It is important that we separate the DOM from the translet. In several
cases we want the DOM as a structure completely independent from the
translet - even though the DOM is a structure internal to XSLTC. One such
case is when transformations are offered by a servlet as a web service.
Any DOM that is built should potentially be stored in a cache and made
available for simultaneous access by several translet/servlet couples.</p>
<p><img src="runtime_type_mapping.gif" alt="runtime_type_mapping.gif"/></p>
<p><ref>Figure 1: Two translets accessing a single dom using different type mappings</ref></p>
</s2><anchor name="mainloop"/>
<s2 title="Main program loop">
<p>The main loop in the translet is found in the <code>applyTemplates()</code>
method. This method goes through these steps:</p>
<ul>
<li>
Get the next node from the node iterator
</li>
<li>
Get the internal type of this node. The DOMAdapter object holds the
internal/external type mapping table, and it will supply the translet
with the internal type of the current node.
</li>
<li>
Execute a switch statement on the internal node type. There will be
one "case" label for each recognised node type - this includes the
first 7 internal node types.
</li>
</ul>
<p>The root node will have internal type 0 and will cause any initial
literal elements to be output. Text nodes will have internal node type 1
and will simply be dumped to the output handler. Unrecognized elements
will have internal node type 3 and will be given the default treatment
(a new iterator is created for the node's children, and this iterator
is passed with a recursive call to <code>applyTemplates()</code>).
Unrecognised attribute nodes (type 4) will be handled like text nodes.
The <code>switch()</code> statement in <code>applyTemplates</code> will thereby
look something like this:</p>
<source>
public void applyTemplates(DOM dom, NodeIterator,
TransletOutputHandler handler) {
// get nodes from iterator
while ((node = iterator.next()) != END) {
// get internal node type
switch(DOM.getType(node)) {
case 0: // root
outputPreable(handler);
break;
case 1: // text
DOM.characters(node,handler);
break;
case 3: // unrecognised element
NodeIterator newIterator = DOM.getChildren(node);
applyTemplates(DOM,newIterator,handler);
break;
case 4: // unrecognised attribute
DOM.characters(node,handler);
break;
case 7: // elements of type <B>
someCompiledCode();
break;
case 8: // elements of type <C>
otherCompiledCode();
break;
default:
break;
}
}
}
</source>
<p>Each recognised element will have its own piece of compiled code.</p>
<p>Note that each "case" will not lead directly to a single template.
There may be several templates that match node type 7
(say <code><B></code>). In the sample stylesheet in the previous chapter
we have to templates that would match a node <code><B></code>. We have
one <code>match="//B"</code> (match just any <code><B></code> element) and
one <code>match="A/B"</code> (match a <code><B></code> element that is a
child of a <code><A></code> element). In this case we would have to
compile code that first gets the type of the current node's parent, and
then compared this type with the type for <code><A></code>. If there was
no match we will have executed the first <code><xsl:for-each></code>
element, but if there was a match we will have executed the last one.
Consequentally, the compiler will generate the following code:</p>
<source>
switch(DOM.getType(node)) {
:
:
case 7: // elements of type <B>
int parent = DOM.getParent(node);
if (DOM.getType(parent) == 9) // type 9 = elements <A>
someCompiledCode();
else
evenOtherCompiledCode();
break;
:
:
}
</source>
<p>We could do the same for namespaces, that is, assign a numeric value
to every namespace that is references in the stylesheet, and use an
<code>"if"</code> statement for each namespace that needs to be checked for
each type. Lets say we had a stylesheet like this:</p>
<source>
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="blahblahblah">
<xsl:template match="/"
xmlns:foo="http://foo.com/spec"
xmlns:bar="http://bar.net/ref">
<xsl:for-each select="foo:A">
<xsl:apply-templates select="." />
</xsl:for-each>
<xsl:for-each select="bar:A">
<xsl:apply-templates select="." />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
</source>
<p>And a stylesheet like this:</p>
<source>
<?xml version="1.0"?>
<DOC
xmlns:foo="http://foo.com/spec"
xmlns:bar="http://bar.net/ref">
<foo:A>In foo namespace</foo:A>
<bar:A>In bar namespace</bar:A>
</DOC>
</source>
<p>We could still keep the same type for all <code><A></code> elements
regardless of what namespace they are in, and use the same <code>"if"</code>
structure within the <code>switch()</code> statement above. The other option
is to assign different types to <code><foo:A></code> and
<code><bar:A></code> elements.</p>
</s2>
</s1>
1.1 xml-xalan/java/xdocs/sources/xsltc/xsltover.xml
Index: xsltover.xml
===================================================================
<?xml version="1.0" standalone="no"?>
<!DOCTYPE s1 SYSTEM "../../style/dtd/document.dtd">
<!--
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 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) 1999, Lotus
* Development Corporation., http://www.lotus.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
-->
<s1 title="XSLT Compiler and Runtime">
<s2 title="Using the Command-Line Utility">
</s2>
</s1>
---------------------------------------------------------------------
To unsubscribe, e-mail: xalan-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xalan-cvs-help@xml.apache.org