1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id: ElemSort.java 468643 2006-10-28 06:56:03Z minchau $
20  */
21 package org.apache.xalan.templates;
22 
23 import org.apache.xalan.res.XSLTErrorResources;
24 import org.apache.xpath.XPath;
25 
26 import org.w3c.dom.DOMException;
27 import org.w3c.dom.Node;
28 
29 /**
30  * Implement xsl:sort.
31  * <pre>
32  * <!ELEMENT xsl:sort EMPTY>
33  * <!ATTLIST xsl:sort
34  *   select %expr; "."
35  *   lang %avt; #IMPLIED
36  *   data-type %avt; "text"
37  *   order %avt; "ascending"
38  *   case-order %avt; #IMPLIED
39  * >
40  * <!-- xsl:sort cannot occur after any other elements or
41  * any non-whitespace character -->
42  * </pre>
43  * @see <a href="http://www.w3.org/TR/xslt#sorting">sorting in XSLT Specification</a>
44  * @xsl.usage advanced
45  */
46 public class ElemSort extends ElemTemplateElement
47 {
48     static final long serialVersionUID = -4991510257335851938L;
49 
50   /**
51    * xsl:sort has a select attribute whose value is an expression.
52    * @serial
53    */
54   private XPath m_selectExpression = null;
55 
56   /**
57    * Set the "select" attribute.
58    * xsl:sort has a select attribute whose value is an expression.
59    * For each node to be processed, the expression is evaluated
60    * with that node as the current node and with the complete
61    * list of nodes being processed in unsorted order as the current
62    * node list. The resulting object is converted to a string as if
63    * by a call to the string function; this string is used as the
64    * sort key for that node. The default value of the select attribute
65    * is ., which will cause the string-value of the current node to
66    * be used as the sort key.
67    *
68    * @param v Value to set for the "select" attribute
69    */
setSelect(XPath v)70   public void setSelect(XPath v)
71   {
72 
73     if (v.getPatternString().indexOf("{") < 0)
74       m_selectExpression = v;
75     else
76       error(XSLTErrorResources.ER_NO_CURLYBRACE, null);
77   }
78 
79   /**
80    * Get the "select" attribute.
81    * xsl:sort has a select attribute whose value is an expression.
82    * For each node to be processed, the expression is evaluated
83    * with that node as the current node and with the complete
84    * list of nodes being processed in unsorted order as the current
85    * node list. The resulting object is converted to a string as if
86    * by a call to the string function; this string is used as the
87    * sort key for that node. The default value of the select attribute
88    * is ., which will cause the string-value of the current node to
89    * be used as the sort key.
90    *
91    * @return The value of the "select" attribute
92    */
getSelect()93   public XPath getSelect()
94   {
95     return m_selectExpression;
96   }
97 
98   /**
99    * lang specifies the language of the sort keys.
100    * @serial
101    */
102   private AVT m_lang_avt = null;
103 
104   /**
105    * Set the "lang" attribute.
106    * lang specifies the language of the sort keys; it has the same
107    * range of values as xml:lang [XML]; if no lang value is
108    * specified, the language should be determined from the system environment.
109    *
110    * @param v The value to set for the "lang" attribute
111    */
setLang(AVT v)112   public void setLang(AVT v)
113   {
114     m_lang_avt = v;
115   }
116 
117   /**
118    * Get the "lang" attribute.
119    * lang specifies the language of the sort keys; it has the same
120    * range of values as xml:lang [XML]; if no lang value is
121    * specified, the language should be determined from the system environment.
122    *
123    * @return The value of the "lang" attribute
124    */
getLang()125   public AVT getLang()
126   {
127     return m_lang_avt;
128   }
129 
130   /**
131    * data-type specifies the data type of the
132    * strings to be sorted.
133    * @serial
134    */
135   private AVT m_dataType_avt = null;
136 
137   /**
138    * Set the "data-type" attribute.
139    * <code>data-type</code> specifies the data type of the
140    * strings; the following values are allowed:
141    * <ul>
142    * <li>
143    * <code>text</code> specifies that the sort keys should be
144    * sorted lexicographically in the culturally correct manner for the
145    * language specified by <code>lang</code>.
146    * </li>
147    * <li>
148    * <code>number</code> specifies that the sort keys should be
149    * converted to numbers and then sorted according to the numeric value;
150    * the sort key is converted to a number as if by a call to the
151    * <b><a href="http://www.w3.org/TR/xpath#function-number">number</a></b> function; the <code>lang</code>
152    * attribute is ignored.
153    * </li>
154    * <li>
155    * A <a href="http://www.w3.org/TR/REC-xml-names#NT-QName">QName</a> with a prefix
156    * is expanded into an <a href="http://www.w3.org/TR/xpath#dt-expanded-name">expanded-name</a> as described
157    * in <a href="#qname">[<b>2.4 Qualified Names</b>]</a>; the expanded-name identifies the data-type;
158    * the behavior in this case is not specified by this document.
159    * </li>
160    * </ul>
161    * <p>The default value is <code>text</code>.</p>
162    * <blockquote>
163    * <b>NOTE: </b>The XSL Working Group plans that future versions of XSLT will
164    * leverage XML Schemas to define further values for this
165    * attribute.</blockquote>
166    *
167    * @param v Value to set for the "data-type" attribute
168    */
setDataType(AVT v)169   public void setDataType(AVT v)
170   {
171     m_dataType_avt = v;
172   }
173 
174   /**
175    * Get the "data-type" attribute.
176    * <code>data-type</code> specifies the data type of the
177    * strings; the following values are allowed:
178    * <ul>
179    * <li>
180    * <code>text</code> specifies that the sort keys should be
181    * sorted lexicographically in the culturally correct manner for the
182    * language specified by <code>lang</code>.
183    * </li>
184    * <li>
185    * <code>number</code> specifies that the sort keys should be
186    * converted to numbers and then sorted according to the numeric value;
187    * the sort key is converted to a number as if by a call to the
188    * <b><a href="http://www.w3.org/TR/xpath#function-number">number</a></b> function; the <code>lang</code>
189    * attribute is ignored.
190    * </li>
191    * <li>
192    * A <a href="http://www.w3.org/TR/REC-xml-names#NT-QName">QName</a> with a prefix
193    * is expanded into an <a href="http://www.w3.org/TR/xpath#dt-expanded-name">expanded-name</a> as described
194    * in <a href="#qname">[<b>2.4 Qualified Names</b>]</a>; the expanded-name identifies the data-type;
195    * the behavior in this case is not specified by this document.
196    * </li>
197    * </ul>
198    * <p>The default value is <code>text</code>.</p>
199    * <blockquote>
200    * <b>NOTE: </b>The XSL Working Group plans that future versions of XSLT will
201    * leverage XML Schemas to define further values for this
202    * attribute.</blockquote>
203    *
204    * @return The value of the "data-type" attribute
205    */
getDataType()206   public AVT getDataType()
207   {
208     return m_dataType_avt;
209   }
210 
211   /**
212    * order specifies whether the strings should be sorted in ascending
213    * or descending order.
214    * @serial
215    */
216   private AVT m_order_avt = null;
217 
218   /**
219    * Set the "order" attribute.
220    * order specifies whether the strings should be sorted in ascending
221    * or descending order; ascending specifies ascending order; descending
222    * specifies descending order; the default is ascending.
223    *
224    * @param v The value to set for the "order" attribute
225    */
setOrder(AVT v)226   public void setOrder(AVT v)
227   {
228     m_order_avt = v;
229   }
230 
231   /**
232    * Get the "order" attribute.
233    * order specifies whether the strings should be sorted in ascending
234    * or descending order; ascending specifies ascending order; descending
235    * specifies descending order; the default is ascending.
236    *
237    * @return The value of the "order" attribute
238    */
getOrder()239   public AVT getOrder()
240   {
241     return m_order_avt;
242   }
243 
244   /**
245    * case-order has the value upper-first or lower-first.
246    * The default value is language dependent.
247    * @serial
248    */
249   private AVT m_caseorder_avt = null;
250 
251   /**
252    * Set the "case-order" attribute.
253    * case-order has the value upper-first or lower-first; this applies
254    * when data-type="text", and specifies that upper-case letters should
255    * sort before lower-case letters or vice-versa respectively.
256    * For example, if lang="en", then A a B b are sorted with
257    * case-order="upper-first" and a A b B are sorted with case-order="lower-first".
258    * The default value is language dependent.
259    *
260    * @param v The value to set for the "case-order" attribute
261    *
262    * @serial
263    */
setCaseOrder(AVT v)264   public void setCaseOrder(AVT v)
265   {
266     m_caseorder_avt = v;
267   }
268 
269   /**
270    * Get the "case-order" attribute.
271    * case-order has the value upper-first or lower-first; this applies
272    * when data-type="text", and specifies that upper-case letters should
273    * sort before lower-case letters or vice-versa respectively.
274    * For example, if lang="en", then A a B b are sorted with
275    * case-order="upper-first" and a A b B are sorted with case-order="lower-first".
276    * The default value is language dependent.
277    *
278    * @return The value of the "case-order" attribute
279    */
getCaseOrder()280   public AVT getCaseOrder()
281   {
282     return m_caseorder_avt;
283   }
284 
285   /**
286    * Get an int constant identifying the type of element.
287    * @see org.apache.xalan.templates.Constants
288    *
289    * @return The token ID of the element
290    */
getXSLToken()291   public int getXSLToken()
292   {
293     return Constants.ELEMNAME_SORT;
294   }
295 
296   /**
297    * Return the node name.
298    *
299    * @return The element's name
300    */
getNodeName()301   public String getNodeName()
302   {
303     return Constants.ELEMNAME_SORT_STRING;
304   }
305 
306   /**
307    * Add a child to the child list.
308    *
309    * @param newChild Child to add to the child list
310    *
311    * @return Child just added to the child list
312    *
313    * @throws DOMException
314    */
appendChild(Node newChild)315   public Node appendChild(Node newChild) throws DOMException
316   {
317 
318     error(XSLTErrorResources.ER_CANNOT_ADD,
319           new Object[]{ newChild.getNodeName(),
320                         this.getNodeName() });  //"Can not add " +((ElemTemplateElement)newChild).m_elemName +
321 
322     //" to " + this.m_elemName);
323     return null;
324   }
325 
326   /**
327    * This function is called after everything else has been
328    * recomposed, and allows the template to set remaining
329    * values that may be based on some other property that
330    * depends on recomposition.
331    */
compose(StylesheetRoot sroot)332   public void compose(StylesheetRoot sroot)
333     throws javax.xml.transform.TransformerException
334   {
335     super.compose(sroot);
336     StylesheetRoot.ComposeState cstate = sroot.getComposeState();
337     java.util.Vector vnames = cstate.getVariableNames();
338     if(null != m_caseorder_avt)
339       m_caseorder_avt.fixupVariables(vnames, cstate.getGlobalsSize());
340     if(null != m_dataType_avt)
341       m_dataType_avt.fixupVariables(vnames, cstate.getGlobalsSize());
342     if(null != m_lang_avt)
343       m_lang_avt.fixupVariables(vnames, cstate.getGlobalsSize());
344     if(null != m_order_avt)
345       m_order_avt.fixupVariables(vnames, cstate.getGlobalsSize());
346     if(null != m_selectExpression)
347       m_selectExpression.fixupVariables(vnames, cstate.getGlobalsSize());
348   }
349 }
350