| <?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> |