| <?xml version="1.0" encoding="UTF-8" standalone="no"?> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
| <html> |
| <head> |
| <title>ASF: <xsl:sort></title> |
| <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> |
| <meta http-equiv="Content-Style-Type" content="text/css" /> |
| <link rel="stylesheet" type="text/css" href="resources/apache-xalan.css" /> |
| </head> |
| <!-- |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| --> |
| <body> |
| <div id="title"> |
| <table class="HdrTitle"> |
| <tbody> |
| <tr> |
| <th rowspan="2"> |
| <a href="../index.html"> |
| <img alt="Trademark Logo" src="resources/XalanJ-Logo-tm.png" width="190" height="90" /> |
| </a> |
| </th> |
| <th text-align="center" width="75%"> |
| <a href="index.html">XSLTC Design</a> |
| </th> |
| </tr> |
| <tr> |
| <td valign="middle"><xsl:sort></td> |
| </tr> |
| </tbody> |
| </table> |
| <table class="HdrButtons" align="center" border="1"> |
| <tbody> |
| <tr> |
| <td> |
| <a href="http://www.apache.org">Apache Foundation</a> |
| </td> |
| <td> |
| <a href="http://xalan.apache.org">Xalan Project</a> |
| </td> |
| <td> |
| <a href="http://xerces.apache.org">Xerces Project</a> |
| </td> |
| <td> |
| <a href="http://www.w3.org/TR">Web Consortium</a> |
| </td> |
| <td> |
| <a href="http://www.oasis-open.org/standards">Oasis Open</a> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div id="navLeft"> |
| <ul> |
| <li> |
| <a href="index.html">Overview</a> |
| </li></ul><hr /><ul> |
| <li> |
| <a href="xsltc_compiler.html">Compiler design</a> |
| </li></ul><hr /><ul> |
| <li> |
| <a href="xsl_whitespace_design.html">Whitespace</a> |
| </li> |
| <li>xsl:sort<br /> |
| </li> |
| <li> |
| <a href="xsl_key_design.html">Keys</a> |
| </li> |
| <li> |
| <a href="xsl_comment_design.html">Comment design</a> |
| </li></ul><hr /><ul> |
| <li> |
| <a href="xsl_lang_design.html">lang()</a> |
| </li> |
| <li> |
| <a href="xsl_unparsed_design.html">Unparsed entities</a> |
| </li></ul><hr /><ul> |
| <li> |
| <a href="xsl_if_design.html">If design</a> |
| </li> |
| <li> |
| <a href="xsl_choose_design.html">Choose|When|Otherwise design</a> |
| </li> |
| <li> |
| <a href="xsl_include_design.html">Include|Import design</a> |
| </li> |
| <li> |
| <a href="xsl_variable_design.html">Variable|Param design</a> |
| </li></ul><hr /><ul> |
| <li> |
| <a href="xsltc_runtime.html">Runtime</a> |
| </li></ul><hr /><ul> |
| <li> |
| <a href="xsltc_dom.html">Internal DOM</a> |
| </li> |
| <li> |
| <a href="xsltc_namespace.html">Namespaces</a> |
| </li></ul><hr /><ul> |
| <li> |
| <a href="xsltc_trax.html">Translet & TrAX</a> |
| </li> |
| <li> |
| <a href="xsltc_predicates.html">XPath Predicates</a> |
| </li> |
| <li> |
| <a href="xsltc_iterators.html">Xsltc Iterators</a> |
| </li> |
| <li> |
| <a href="xsltc_native_api.html">Xsltc Native API</a> |
| </li> |
| <li> |
| <a href="xsltc_trax_api.html">Xsltc TrAX API</a> |
| </li> |
| <li> |
| <a href="xsltc_performance.html">Performance Hints</a> |
| </li> |
| </ul> |
| </div> |
| <div id="content"> |
| <h2><xsl:sort></h2> |
| |
| <ul> |
| <li> |
| <a href="#functionality">Functionality</a> |
| </li> |
| <li> |
| <a href="#sort-class">The Sort class</a> |
| </li> |
| <li> |
| <a href="#iterator">The SortingIterator class</a> |
| </li> |
| <li> |
| <a href="#sortrecord">The NodeSortRecord class</a> |
| </li> |
| <li> |
| <a href="#recordfactory">The NodeSortRecordFactory class</a> |
| </li> |
| </ul> |
| |
| <a name="functionality"></a> |
| <p align="right" size="2"> |
| <a href="#content">(top)</a> |
| </p> |
| <h3>Functionality</h3> |
| |
| <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> |
| |
| <a name="sort-class"></a> |
| <p align="right" size="2"> |
| <a href="#content">(top)</a> |
| </p> |
| <h3>The Sort class</h3> |
| |
| <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> |
| |
| <a name="iterator"></a> |
| <p align="right" size="2"> |
| <a href="#content">(top)</a> |
| </p> |
| <h3>The SortingIterator class</h3> |
| |
| <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> |
| <b> |
| <i>Figure 1: SortingIterator</i> |
| </b> |
| </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> |
| |
| <a name="sortrecord"></a> |
| <p align="right" size="2"> |
| <a href="#content">(top)</a> |
| </p> |
| <h3>The NodeSortRecord class</h3> |
| |
| <p>The static methods in the Sort class generates a class inheriting from |
| NodeSortRecord, with the following overloaded methods:</p> |
| |
| <ul> |
| <li> |
| <b>Class Constructor</b> |
| </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> |
| |
| <blockquote class="source"> |
| <pre> |
| /** |
| * 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); |
| } |
| </pre> |
| </blockquote> |
| |
| <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> |
| |
| <a name="recordfactory"></a> |
| <p align="right" size="2"> |
| <a href="#content">(top)</a> |
| </p> |
| <h3>The NodeSortRecordFactory class</h3> |
| |
| <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> |
| |
| |
| <p align="right" size="2"> |
| <a href="#content">(top)</a> |
| </p> |
| </div> |
| <div id="footer">Copyright © 1999-2014 The Apache Software Foundation<br />Apache, Xalan, and the Feather logo are trademarks of The Apache Software Foundation<div class="small">Web Page created on - Thu 2014-05-15</div> |
| </div> |
| </body> |
| </html> |