KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > templates > StylesheetRoot


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: StylesheetRoot.java,v 1.54 2004/02/16 20:32:32 minchau Exp $
18  */

19 package org.apache.xalan.templates;
20
21 import java.text.DecimalFormatSymbols JavaDoc;
22 import java.util.Hashtable JavaDoc;
23 import java.util.Properties JavaDoc;
24 import java.util.Vector JavaDoc;
25
26 import javax.xml.transform.ErrorListener JavaDoc;
27 import javax.xml.transform.Templates JavaDoc;
28 import javax.xml.transform.Transformer JavaDoc;
29 import javax.xml.transform.TransformerConfigurationException JavaDoc;
30 import javax.xml.transform.TransformerException JavaDoc;
31
32 import org.apache.xalan.extensions.ExtensionNamespacesManager;
33 import org.apache.xalan.processor.XSLTSchema;
34 import org.apache.xalan.res.XSLMessages;
35 import org.apache.xalan.res.XSLTErrorResources;
36
37 import org.apache.xalan.transformer.TransformerImpl;
38 import org.apache.xml.dtm.DTM;
39 import org.apache.xml.dtm.ref.ExpandedNameTable;
40 import org.apache.xml.utils.IntStack;
41 import org.apache.xml.utils.QName;
42 import org.apache.xpath.XPath;
43 import org.apache.xpath.XPathContext;
44
45 /**
46  * This class represents the root object of the stylesheet tree.
47  * @xsl.usage general
48  */

49 public class StylesheetRoot extends StylesheetComposed
50         implements java.io.Serializable JavaDoc, Templates JavaDoc
51 {
52
53   /**
54    * Uses an XSL stylesheet document.
55    * @throws TransformerConfigurationException if the baseIdentifier can not be resolved to a URL.
56    */

57   public StylesheetRoot(ErrorListener JavaDoc errorListener) throws TransformerConfigurationException JavaDoc
58   {
59
60     super(null);
61
62     setStylesheetRoot(this);
63
64     try
65     {
66       m_selectDefault = new XPath("node()", this, this, XPath.SELECT, errorListener);
67
68       initDefaultRule(errorListener);
69     }
70     catch (TransformerException JavaDoc se)
71     {
72       throw new TransformerConfigurationException JavaDoc(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_INIT_DEFAULT_TEMPLATES, null), se); //"Can't init default templates!", se);
73
}
74   }
75
76   /**
77    * The schema used when creating this StylesheetRoot
78    * @serial
79    */

80   private Hashtable JavaDoc m_availElems;
81   
82   /**
83    * Creates a StylesheetRoot and retains a pointer to the schema used to create this
84    * StylesheetRoot. The schema may be needed later for an element-available() function call.
85    *
86    * @param schema The schema used to create this stylesheet
87    * @throws TransformerConfigurationException if the baseIdentifier can not be resolved to a URL.
88    */

89   public StylesheetRoot(XSLTSchema schema, ErrorListener JavaDoc listener) throws TransformerConfigurationException JavaDoc
90   {
91
92     this(listener);
93     m_availElems = schema.getElemsAvailable();
94   }
95
96   /**
97    * Tell if this is the root of the stylesheet tree.
98    *
99    * @return True since this is the root of the stylesheet tree.
100    */

101   public boolean isRoot()
102   {
103     return true;
104   }
105
106   /**
107    * Get the hashtable of available elements.
108    *
109    * @return table of available elements, keyed by qualified names, and with
110    * values of the same qualified names.
111    */

112   public Hashtable JavaDoc getAvailableElements()
113   {
114     return m_availElems;
115   }
116   
117   private ExtensionNamespacesManager m_extNsMgr = null;
118   
119   /**
120    * Only instantiate an ExtensionNamespacesManager if one is called for
121    * (i.e., if the stylesheet contains extension functions and/or elements).
122    */

123   public ExtensionNamespacesManager getExtensionNamespacesManager()
124   {
125      if (m_extNsMgr == null)
126        m_extNsMgr = new ExtensionNamespacesManager();
127      return m_extNsMgr;
128   }
129   
130   /**
131    * Get the vector of extension namespaces. Used to provide
132    * the extensions table access to a list of extension
133    * namespaces encountered during composition of a stylesheet.
134    */

135   public Vector JavaDoc getExtensions()
136   {
137     return m_extNsMgr != null ? m_extNsMgr.getExtensions() : null;
138   }
139
140 /*
141   public void runtimeInit(TransformerImpl transformer) throws TransformerException
142   {
143     System.out.println("StylesheetRoot.runtimeInit()");
144       
145   // try{throw new Exception("StylesheetRoot.runtimeInit()");} catch(Exception e){e.printStackTrace();}
146
147     }
148 */

149
150   //============== Templates Interface ================
151

152   /**
153    * Create a new transformation context for this Templates object.
154    *
155    * @return A Transformer instance, never null.
156    */

157   public Transformer JavaDoc newTransformer()
158   {
159     return new TransformerImpl(this);
160   }
161   
162
163   public Properties JavaDoc getDefaultOutputProps()
164   {
165     return m_outputProperties.getProperties();
166   }
167   
168   /**
169    * Get the static properties for xsl:output. The object returned will
170    * be a clone of the internal values, and thus it can be mutated
171    * without mutating the Templates object, and then handed in to
172    * the process method.
173    *
174    * <p>For XSLT, Attribute Value Templates attribute values will
175    * be returned unexpanded (since there is no context at this point).</p>
176    *
177    * @return A Properties object, not null.
178    */

179   public Properties JavaDoc getOutputProperties()
180   {
181     return (Properties JavaDoc)getDefaultOutputProps().clone();
182   }
183
184   //============== End Templates Interface ================
185

186   /**
187    * Recompose the values of all "composed" properties, meaning
188    * properties that need to be combined or calculated from
189    * the combination of imported and included stylesheets. This
190    * method determines the proper import precedence of all imported
191    * stylesheets. It then iterates through all of the elements and
192    * properties in the proper order and triggers the individual recompose
193    * methods.
194    *
195    * @throws TransformerException
196    */

197   public void recompose() throws TransformerException JavaDoc
198   {
199     // Now we make a Vector that is going to hold all of the recomposable elements
200

201       Vector JavaDoc recomposableElements = new Vector JavaDoc();
202
203     // First, we build the global import tree.
204

205     if (null == m_globalImportList)
206     {
207
208       Vector JavaDoc importList = new Vector JavaDoc();
209
210       addImports(this, true, importList);
211
212       // Now we create an array and reverse the order of the importList vector.
213
// We built the importList vector backwards so that we could use addElement
214
// to append to the end of the vector instead of constantly pushing new
215
// stylesheets onto the front of the vector and having to shift the rest
216
// of the vector each time.
217

218       m_globalImportList = new StylesheetComposed[importList.size()];
219
220       for (int i = 0, j= importList.size() -1; i < importList.size(); i++)
221       {
222         m_globalImportList[j] = (StylesheetComposed) importList.elementAt(i);
223         // Build the global include list for this stylesheet.
224
// This needs to be done ahead of the recomposeImports
225
// because we need the info from the composed includes.
226
m_globalImportList[j].recomposeIncludes(m_globalImportList[j]);
227         // Calculate the number of this import.
228
m_globalImportList[j--].recomposeImports();
229       }
230     }
231     // Next, we walk the import tree and add all of the recomposable elements to the vector.
232
int n = getGlobalImportCount();
233
234     for (int i = 0; i < n; i++)
235     {
236       StylesheetComposed imported = getGlobalImport(i);
237       imported.recompose(recomposableElements);
238     }
239
240     // We sort the elements into ascending order.
241

242     QuickSort2(recomposableElements, 0, recomposableElements.size() - 1);
243
244     // We set up the global variables that will hold the recomposed information.
245

246
247     m_outputProperties = new OutputProperties(org.apache.xml.serializer.Method.UNKNOWN);
248 // m_outputProperties = new OutputProperties(Method.XML);
249

250     m_attrSets = new Hashtable JavaDoc();
251     m_decimalFormatSymbols = new Hashtable JavaDoc();
252     m_keyDecls = new Vector JavaDoc();
253     m_namespaceAliasComposed = new Hashtable JavaDoc();
254     m_templateList = new TemplateList();
255     m_variables = new Vector JavaDoc();
256
257     // Now we sequence through the sorted elements,
258
// calling the recompose() function on each one. This will call back into the
259
// appropriate routine here to actually do the recomposition.
260
// Note that we're going backwards, encountering the highest precedence items first.
261
for (int i = recomposableElements.size() - 1; i >= 0; i--)
262       ((ElemTemplateElement) recomposableElements.elementAt(i)).recompose(this);
263     
264 /*
265  * Backing out REE again, as it seems to cause some new failures
266  * which need to be investigated. -is
267  */

268     // This has to be done before the initialization of the compose state, because
269
// eleminateRedundentGlobals will add variables to the m_variables vector, which
270
// it then copied in the ComposeState constructor.
271

272 // if(true && org.apache.xalan.processor.TransformerFactoryImpl.m_optimize)
273
// {
274
// RedundentExprEliminator ree = new RedundentExprEliminator();
275
// callVisitors(ree);
276
// ree.eleminateRedundentGlobals(this);
277
// }
278

279     initComposeState();
280
281     // Need final composition of TemplateList. This adds the wild cards onto the chains.
282
m_templateList.compose(this);
283     
284     // Need to clear check for properties at the same import level.
285
m_outputProperties.compose(this);
286     m_outputProperties.endCompose(this);
287     
288     // Now call the compose() method on every element to give it a chance to adjust
289
// based on composed values.
290

291     n = getGlobalImportCount();
292
293     for (int i = 0; i < n; i++)
294     {
295       StylesheetComposed imported = this.getGlobalImport(i);
296       int includedCount = imported.getIncludeCountComposed();
297       for (int j = -1; j < includedCount; j++)
298       {
299         Stylesheet included = imported.getIncludeComposed(j);
300         composeTemplates(included);
301       }
302     }
303     // Attempt to register any remaining unregistered extension namespaces.
304
if (m_extNsMgr != null)
305       m_extNsMgr.registerUnregisteredNamespaces();
306
307     clearComposeState();
308   }
309
310   /**
311    * Call the compose function for each ElemTemplateElement.
312    *
313    * @param templ non-null reference to template element that will have
314    * the composed method called on it, and will have it's children's composed
315    * methods called.
316    */

317   void composeTemplates(ElemTemplateElement templ) throws TransformerException JavaDoc
318   {
319
320     templ.compose(this);
321
322     for (ElemTemplateElement child = templ.getFirstChildElem();
323             child != null; child = child.getNextSiblingElem())
324     {
325       composeTemplates(child);
326     }
327     
328     templ.endCompose(this);
329   }
330
331   /**
332    * The combined list of imports. The stylesheet with the highest
333    * import precedence will be at element 0. The one with the lowest
334    * import precedence will be at element length - 1.
335    * @serial
336    */

337   private StylesheetComposed[] m_globalImportList;
338
339   /**
340    * Add the imports in the given sheet to the working importList vector.
341    * The will be added from highest import precedence to
342    * least import precedence. This is a post-order traversal of the
343    * import tree as described in <a HREF="http://www.w3.org/TR/xslt.html#import">the
344    * XSLT Recommendation</a>.
345    * <p>For example, suppose</p>
346    * <p>stylesheet A imports stylesheets B and C in that order;</p>
347    * <p>stylesheet B imports stylesheet D;</p>
348    * <p>stylesheet C imports stylesheet E.</p>
349    * <p>Then the order of import precedence (highest first) is
350    * A, C, E, B, D.</p>
351    *
352    * @param stylesheet Stylesheet to examine for imports.
353    * @param addToList <code>true</code> if this template should be added to the import list
354    * @param importList The working import list. Templates are added here in the reverse
355    * order of priority. When we're all done, we'll reverse this to the correct
356    * priority in an array.
357    */

358   protected void addImports(Stylesheet stylesheet, boolean addToList, Vector JavaDoc importList)
359   {
360
361     // Get the direct imports of this sheet.
362

363     int n = stylesheet.getImportCount();
364
365     if (n > 0)
366     {
367       for (int i = 0; i < n; i++)
368       {
369         Stylesheet imported = stylesheet.getImport(i);
370
371         addImports(imported, true, importList);
372       }
373     }
374
375     n = stylesheet.getIncludeCount();
376
377     if (n > 0)
378     {
379       for (int i = 0; i < n; i++)
380       {
381         Stylesheet included = stylesheet.getInclude(i);
382
383         addImports(included, false, importList);
384       }
385     }
386
387     if (addToList)
388       importList.addElement(stylesheet);
389
390   }
391
392   /**
393    * Get a stylesheet from the global import list.
394    * TODO: JKESS PROPOSES SPECIAL-CASE FOR NO IMPORT LIST, TO MATCH COUNT.
395    *
396    * @param i Index of stylesheet to get from global import list
397    *
398    * @return The stylesheet at the given index
399    */

400   public StylesheetComposed getGlobalImport(int i)
401   {
402     return m_globalImportList[i];
403   }
404
405   /**
406    * Get the total number of imports in the global import list.
407    *
408    * @return The total number of imported stylesheets, including
409    * the root stylesheet, thus the number will always be 1 or
410    * greater.
411    * TODO: JKESS PROPOSES SPECIAL-CASE FOR NO IMPORT LIST, TO MATCH DESCRIPTION.
412    */

413   public int getGlobalImportCount()
414   {
415           return (m_globalImportList!=null)
416                         ? m_globalImportList.length
417                           : 1;
418   }
419
420   /**
421    * Given a stylesheet, return the number of the stylesheet
422    * in the global import list.
423    * @param sheet The stylesheet which will be located in the
424    * global import list.
425    * @return The index into the global import list of the given stylesheet,
426    * or -1 if it is not found (which should never happen).
427    */

428   public int getImportNumber(StylesheetComposed sheet)
429   {
430
431     if (this == sheet)
432       return 0;
433
434     int n = getGlobalImportCount();
435
436     for (int i = 0; i < n; i++)
437     {
438       if (sheet == getGlobalImport(i))
439         return i;
440     }
441
442     return -1;
443   }
444
445   /**
446    * This will be set up with the default values, and then the values
447    * will be set as stylesheets are encountered.
448    * @serial
449    */

450   private OutputProperties m_outputProperties;
451
452   /**
453    * Recompose the output format object from the included elements.
454    *
455    * @param oprops non-null reference to xsl:output properties representation.
456    */

457   void recomposeOutput(OutputProperties oprops)
458     throws TransformerException JavaDoc
459   {
460     
461     m_outputProperties.copyFrom(oprops);
462   }
463
464   /**
465    * Get the combined "xsl:output" property with the properties
466    * combined from the included stylesheets. If a xsl:output
467    * is not declared in this stylesheet or an included stylesheet,
468    * look in the imports.
469    * Please note that this returns a reference to the OutputProperties
470    * object, not a cloned object, like getOutputProperties does.
471    * @see <a HREF="http://www.w3.org/TR/xslt#output">output in XSLT Specification</a>
472    *
473    * @return non-null reference to composed output properties object.
474    */

475   public OutputProperties getOutputComposed()
476   {
477
478     // System.out.println("getOutputComposed.getIndent: "+m_outputProperties.getIndent());
479
// System.out.println("getOutputComposed.getIndenting: "+m_outputProperties.getIndenting());
480
return m_outputProperties;
481   }
482
483   /** Flag indicating whether an output method has been set by the user.
484    * @serial */

485   private boolean m_outputMethodSet = false;
486
487   /**
488    * Find out if an output method has been set by the user.
489    *
490    * @return Value indicating whether an output method has been set by the user
491    * @xsl.usage internal
492    */

493   public boolean isOutputMethodSet()
494   {
495     return m_outputMethodSet;
496   }
497
498   /**
499    * Composed set of all included and imported attribute set properties.
500    * Each entry is a vector of ElemAttributeSet objects.
501    * @serial
502    */

503   private Hashtable JavaDoc m_attrSets;
504
505   /**
506    * Recompose the attribute-set declarations.
507    *
508    * @param attrSet An attribute-set to add to the hashtable of attribute sets.
509    */

510   void recomposeAttributeSets(ElemAttributeSet attrSet)
511   {
512     Vector JavaDoc attrSetList = (Vector JavaDoc) m_attrSets.get(attrSet.getName());
513
514     if (null == attrSetList)
515     {
516       attrSetList = new Vector JavaDoc();
517
518       m_attrSets.put(attrSet.getName(), attrSetList);
519     }
520
521     attrSetList.addElement(attrSet);
522   }
523
524   /**
525    * Get a list "xsl:attribute-set" properties that match the qname.
526    * @see <a HREF="http://www.w3.org/TR/xslt#attribute-sets">attribute-sets in XSLT Specification</a>
527    *
528    * @param name Qualified name of attribute set properties to get
529    *
530    * @return A vector of attribute sets matching the given name
531    *
532    * @throws ArrayIndexOutOfBoundsException
533    */

534   public Vector JavaDoc getAttributeSetComposed(QName name)
535           throws ArrayIndexOutOfBoundsException JavaDoc
536   {
537     return (Vector JavaDoc) m_attrSets.get(name);
538   }
539
540   /**
541    * Table of DecimalFormatSymbols, keyed by QName.
542    * @serial
543    */

544   private Hashtable JavaDoc m_decimalFormatSymbols;
545
546   /**
547    * Recompose the decimal-format declarations.
548    *
549    * @param dfp A DecimalFormatProperties to add to the hashtable of decimal formats.
550    */

551   void recomposeDecimalFormats(DecimalFormatProperties dfp)
552   {
553     DecimalFormatSymbols JavaDoc oldDfs =
554                   (DecimalFormatSymbols JavaDoc) m_decimalFormatSymbols.get(dfp.getName());
555     if (null == oldDfs)
556     {
557       m_decimalFormatSymbols.put(dfp.getName(), dfp.getDecimalFormatSymbols());
558     }
559     else if (!dfp.getDecimalFormatSymbols().equals(oldDfs))
560     {
561       String JavaDoc themsg;
562       if (dfp.getName().equals(new QName("")))
563       {
564         // "Only one default xsl:decimal-format declaration is allowed."
565
themsg = XSLMessages.createWarning(
566                           XSLTErrorResources.WG_ONE_DEFAULT_XSLDECIMALFORMAT_ALLOWED,
567                           new Object JavaDoc[0]);
568       }
569       else
570       {
571         // "xsl:decimal-format names must be unique. Name {0} has been duplicated."
572
themsg = XSLMessages.createWarning(
573                           XSLTErrorResources.WG_XSLDECIMALFORMAT_NAMES_MUST_BE_UNIQUE,
574                           new Object JavaDoc[] {dfp.getName()});
575       }
576
577       error(themsg); // Should we throw TransformerException instead?
578
}
579
580   }
581
582   /**
583    * Given a valid element decimal-format name, return the
584    * decimalFormatSymbols with that name.
585    * <p>It is an error to declare either the default decimal-format or
586    * a decimal-format with a given name more than once (even with
587    * different import precedence), unless it is declared every
588    * time with the same value for all attributes (taking into
589    * account any default values).</p>
590    * <p>Which means, as far as I can tell, the decimal-format
591    * properties are not additive.</p>
592    *
593    * @param name Qualified name of the decimal format to find
594    * @return DecimalFormatSymbols object matching the given name or
595    * null if name is not found.
596    */

597   public DecimalFormatSymbols JavaDoc getDecimalFormatComposed(QName name)
598   {
599     return (DecimalFormatSymbols JavaDoc) m_decimalFormatSymbols.get(name);
600   }
601
602   /**
603    * A list of all key declarations visible from this stylesheet and all
604    * lesser stylesheets.
605    * @serial
606    */

607   private Vector JavaDoc m_keyDecls;
608
609   /**
610    * Recompose the key declarations.
611    *
612    * @param keyDecl A KeyDeclaration to be added to the vector of key declarations.
613    */

614   void recomposeKeys(KeyDeclaration keyDecl)
615   {
616     m_keyDecls.addElement(keyDecl);
617   }
618
619   /**
620    * Get the composed "xsl:key" properties.
621    * @see <a HREF="http://www.w3.org/TR/xslt#key">key in XSLT Specification</a>
622    *
623    * @return A vector of the composed "xsl:key" properties.
624    */

625   public Vector JavaDoc getKeysComposed()
626   {
627     return m_keyDecls;
628   }
629
630   /**
631    * Composed set of all namespace aliases.
632    * @serial
633    */

634   private Hashtable JavaDoc m_namespaceAliasComposed;
635
636   /**
637    * Recompose the namespace-alias declarations.
638    *
639    * @param nsAlias A NamespaceAlias object to add to the hashtable of namespace aliases.
640    */

641   void recomposeNamespaceAliases(NamespaceAlias nsAlias)
642   {
643     m_namespaceAliasComposed.put(nsAlias.getStylesheetNamespace(),
644                                  nsAlias);
645   }
646
647   /**
648    * Get the "xsl:namespace-alias" property.
649    * Return the NamespaceAlias for a given namespace uri.
650    * @see <a HREF="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a>
651    *
652    * @param uri non-null reference to namespace that is to be aliased.
653    *
654    * @return NamespaceAlias that matches uri, or null if no match.
655    */

656   public NamespaceAlias getNamespaceAliasComposed(String JavaDoc uri)
657   {
658     return (NamespaceAlias) ((null == m_namespaceAliasComposed)
659                     ? null : m_namespaceAliasComposed.get(uri));
660   }
661
662   /**
663    * The "xsl:template" properties.
664    * @serial
665    */

666   private TemplateList m_templateList;
667
668   /**
669    * Recompose the template declarations.
670    *
671    * @param template An ElemTemplate object to add to the template list.
672    */

673   void recomposeTemplates(ElemTemplate template)
674   {
675     m_templateList.setTemplate(template);
676   }
677
678   /**
679    * Accessor method to retrieve the <code>TemplateList</code> associated with
680    * this StylesheetRoot.
681    *
682    * @return The composed <code>TemplateList</code>.
683    */

684   public final TemplateList getTemplateListComposed()
685   {
686     return m_templateList;
687   }
688
689   /**
690    * Mutator method to set the <code>TemplateList</code> associated with this
691    * StylesheetRoot. This method should only be used by the compiler. Normally,
692    * the template list is built during the recompose process and should not be
693    * altered by the user.
694    * @param templateList The new <code>TemplateList</code> for this StylesheetRoot.
695    */

696   public final void setTemplateListComposed(TemplateList templateList)
697   {
698     m_templateList = templateList;
699   }
700
701   /**
702    * Get an "xsl:template" property by node match. This looks in the imports as
703    * well as this stylesheet.
704    * @see <a HREF="http://www.w3.org/TR/xslt#section-Defining-Template-Rules">section-Defining-Template-Rules in XSLT Specification</a>
705    *
706    * @param xctxt non-null reference to XPath runtime execution context.
707    * @param targetNode non-null reference of node that the template must match.
708    * @param mode qualified name of the node, or null.
709    * @param quietConflictWarnings true if conflict warnings should not be reported.
710    *
711    * @return reference to ElemTemplate that is the best match for targetNode, or
712    * null if no match could be made.
713    *
714    * @throws TransformerException
715    */

716   public ElemTemplate getTemplateComposed(XPathContext xctxt,
717                                           int targetNode,
718                                           QName mode,
719                                           boolean quietConflictWarnings,
720                                           DTM dtm)
721             throws TransformerException JavaDoc
722   {
723     return m_templateList.getTemplate(xctxt, targetNode, mode,
724                                       quietConflictWarnings,
725                                       dtm);
726   }
727   
728   /**
729    * Get an "xsl:template" property by node match. This looks in the imports as
730    * well as this stylesheet.
731    * @see <a HREF="http://www.w3.org/TR/xslt#section-Defining-Template-Rules">section-Defining-Template-Rules in XSLT Specification</a>
732    *
733    * @param xctxt non-null reference to XPath runtime execution context.
734    * @param targetNode non-null reference of node that the template must match.
735    * @param mode qualified name of the node, or null.
736    * @param maxImportLevel The maximum importCountComposed that we should consider or -1
737    * if we should consider all import levels. This is used by apply-imports to
738    * access templates that have been overridden.
739    * @param endImportLevel The count of composed imports
740    * @param quietConflictWarnings true if conflict warnings should not be reported.
741    *
742    * @return reference to ElemTemplate that is the best match for targetNode, or
743    * null if no match could be made.
744    *
745    * @throws TransformerException
746    */

747   public ElemTemplate getTemplateComposed(XPathContext xctxt,
748                                           int targetNode,
749                                           QName mode,
750                                           int maxImportLevel, int endImportLevel,
751                                           boolean quietConflictWarnings,
752                                           DTM dtm)
753             throws TransformerException JavaDoc
754   {
755     return m_templateList.getTemplate(xctxt, targetNode, mode,
756                                       maxImportLevel, endImportLevel,
757                                       quietConflictWarnings,
758                                       dtm);
759   }
760
761   /**
762    * Get an "xsl:template" property. This looks in the imports as
763    * well as this stylesheet.
764    * @see <a HREF="http://www.w3.org/TR/xslt#section-Defining-Template-Rules">section-Defining-Template-Rules in XSLT Specification</a>
765    *
766    * @param qname non-null reference to qualified name of template.
767    *
768    * @return reference to named template, or null if not found.
769    */

770   public ElemTemplate getTemplateComposed(QName qname)
771   {
772     return m_templateList.getTemplate(qname);
773   }
774   
775   /**
776    * Composed set of all variables and params.
777    * @serial
778    */

779   private Vector JavaDoc m_variables;
780
781   /**
782    * Recompose the top level variable and parameter declarations.
783    *
784    * @param elemVar A top level variable or parameter to be added to the Vector.
785    */

786   void recomposeVariables(ElemVariable elemVar)
787   {
788     // Don't overide higher priority variable
789
if (getVariableOrParamComposed(elemVar.getName()) == null)
790     {
791       elemVar.setIsTopLevel(true); // Mark as a top-level variable or param
792
elemVar.setIndex(m_variables.size());
793       m_variables.addElement(elemVar);
794     }
795   }
796
797   /**
798    * Get an "xsl:variable" property.
799    * @see <a HREF="http://www.w3.org/TR/xslt#top-level-variables">top-level-variables in XSLT Specification</a>
800    *
801    * @param qname Qualified name of variable or param
802    *
803    * @return The ElemVariable with the given qualified name
804    */

805   public ElemVariable getVariableOrParamComposed(QName qname)
806   {
807     if (null != m_variables)
808     {
809       int n = m_variables.size();
810
811       for (int i = 0; i < n; i++)
812       {
813         ElemVariable var = (ElemVariable)m_variables.elementAt(i);
814         if(var.getName().equals(qname))
815           return var;
816       }
817     }
818
819     return null;
820   }
821
822   /**
823    * Get all global "xsl:variable" properties in scope for this stylesheet.
824    * @see <a HREF="http://www.w3.org/TR/xslt#top-level-variables">top-level-variables in XSLT Specification</a>
825    *
826    * @return Vector of all variables and params in scope
827    */

828   public Vector JavaDoc getVariablesAndParamsComposed()
829   {
830     return m_variables;
831   }
832
833   /**
834    * A list of properties that specify how to do space
835    * stripping. This uses the same exact mechanism as Templates.
836    * @serial
837    */

838   private TemplateList m_whiteSpaceInfoList;
839
840   /**
841    * Recompose the strip-space and preserve-space declarations.
842    *
843    * @param wsi A WhiteSpaceInfo element to add to the list of WhiteSpaceInfo elements.
844    */

845   void recomposeWhiteSpaceInfo(WhiteSpaceInfo wsi)
846   {
847     if (null == m_whiteSpaceInfoList)
848       m_whiteSpaceInfoList = new TemplateList();
849
850     m_whiteSpaceInfoList.setTemplate(wsi);
851   }
852
853   /**
854    * Check to see if the caller should bother with check for
855    * whitespace nodes.
856    *
857    * @return Whether the caller should bother with check for
858    * whitespace nodes.
859    */

860   public boolean shouldCheckWhitespace()
861   {
862     return null != m_whiteSpaceInfoList;
863   }
864
865   /**
866    * Get information about whether or not an element should strip whitespace.
867    * @see <a HREF="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
868    *
869    * @param support The XPath runtime state.
870    * @param targetElement Element to check
871    *
872    * @return WhiteSpaceInfo for the given element
873    *
874    * @throws TransformerException
875    */

876   public WhiteSpaceInfo getWhiteSpaceInfo(
877           XPathContext support, int targetElement, DTM dtm) throws TransformerException JavaDoc
878   {
879
880     if (null != m_whiteSpaceInfoList)
881       return (WhiteSpaceInfo) m_whiteSpaceInfoList.getTemplate(support,
882               targetElement, null, false, dtm);
883     else
884       return null;
885   }
886   
887   /**
888    * Get information about whether or not an element should strip whitespace.
889    * @see <a HREF="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
890    *
891    * @param support The XPath runtime state.
892    * @param targetElement Element to check
893    *
894    * @return true if the whitespace should be stripped.
895    *
896    * @throws TransformerException
897    */

898   public boolean shouldStripWhiteSpace(
899           XPathContext support, int targetElement) throws TransformerException JavaDoc
900   {
901     if (null != m_whiteSpaceInfoList)
902     {
903       while(DTM.NULL != targetElement)
904       {
905         DTM dtm = support.getDTM(targetElement);
906         WhiteSpaceInfo info = (WhiteSpaceInfo) m_whiteSpaceInfoList.getTemplate(support,
907                 targetElement, null, false, dtm);
908         if(null != info)
909           return info.getShouldStripSpace();
910         
911         int parent = dtm.getParent(targetElement);
912         if(DTM.NULL != parent && DTM.ELEMENT_NODE == dtm.getNodeType(parent))
913           targetElement = parent;
914         else
915           targetElement = DTM.NULL;
916       }
917     }
918     return false;
919   }
920   
921   /**
922    * Get information about whether or not whitespace can be stripped.
923    * @see <a HREF="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
924    *
925    * @return true if the whitespace can be stripped.
926    */

927   public boolean canStripWhiteSpace()
928   {
929     return (null != m_whiteSpaceInfoList);
930   }
931   
932
933
934   /**
935    * The default template to use for text nodes if we don't find
936    * anything else. This is initialized in initDefaultRule().
937    * @serial
938    * @xsl.usage advanced
939    */

940   private ElemTemplate m_defaultTextRule;
941
942   /**
943    * Get the default template for text.
944    *
945    * @return the default template for text.
946    * @xsl.usage advanced
947    */

948   public final ElemTemplate getDefaultTextRule()
949   {
950     return m_defaultTextRule;
951   }
952
953   /**
954    * The default template to use if we don't find anything
955    * else. This is initialized in initDefaultRule().
956    * @serial
957    * @xsl.usage advanced
958    */

959   private ElemTemplate m_defaultRule;
960
961   /**
962    * Get the default template for elements.
963    *
964    * @return the default template for elements.
965    * @xsl.usage advanced
966    */

967   public final ElemTemplate getDefaultRule()
968   {
969     return m_defaultRule;
970   }
971
972   /**
973    * The default template to use for the root if we don't find
974    * anything else. This is initialized in initDefaultRule().
975    * We kind of need this because the defaultRule isn't good
976    * enough because it doesn't supply a document context.
977    * For now, I default the root document element to "HTML".
978    * Don't know if this is really a good idea or not.
979    * I suspect it is not.
980    * @serial
981    * @xsl.usage advanced
982    */

983   private ElemTemplate m_defaultRootRule;
984
985   /**
986    * Get the default template for a root node.
987    *
988    * @return The default template for a root node.
989    * @xsl.usage advanced
990    */

991   public final ElemTemplate getDefaultRootRule()
992   {
993     return m_defaultRootRule;
994   }
995   
996   /**
997    * The start rule to kick off the transformation.
998    * @serial
999    * @xsl.usage advanced
1000   */

1001  private ElemTemplate m_startRule;
1002
1003  /**
1004   * Get the default template for a root node.
1005   *
1006   * @return The default template for a root node.
1007   * @xsl.usage advanced
1008   */

1009  public final ElemTemplate getStartRule()
1010  {
1011    return m_startRule;
1012  }
1013
1014
1015  /**
1016   * Used for default selection.
1017   * @serial
1018   */

1019  XPath m_selectDefault;
1020
1021  /**
1022   * Create the default rule if needed.
1023   *
1024   * @throws TransformerException
1025   */

1026  private void initDefaultRule(ErrorListener JavaDoc errorListener) throws TransformerException JavaDoc
1027  {
1028
1029    // Then manufacture a default
1030
m_defaultRule = new ElemTemplate();
1031
1032    m_defaultRule.setStylesheet(this);
1033
1034    XPath defMatch = new XPath("*", this, this, XPath.MATCH, errorListener);
1035
1036    m_defaultRule.setMatch(defMatch);
1037
1038    ElemApplyTemplates childrenElement = new ElemApplyTemplates();
1039
1040    childrenElement.setIsDefaultTemplate(true);
1041    childrenElement.setSelect(m_selectDefault);
1042    m_defaultRule.appendChild(childrenElement);
1043    
1044    m_startRule = m_defaultRule;
1045
1046    // -----------------------------
1047
m_defaultTextRule = new ElemTemplate();
1048
1049    m_defaultTextRule.setStylesheet(this);
1050
1051    defMatch = new XPath("text() | @*", this, this, XPath.MATCH, errorListener);
1052
1053    m_defaultTextRule.setMatch(defMatch);
1054
1055    ElemValueOf elemValueOf = new ElemValueOf();
1056
1057    m_defaultTextRule.appendChild(elemValueOf);
1058
1059    XPath selectPattern = new XPath(".", this, this, XPath.SELECT, errorListener);
1060
1061    elemValueOf.setSelect(selectPattern);
1062
1063    //--------------------------------
1064
m_defaultRootRule = new ElemTemplate();
1065
1066    m_defaultRootRule.setStylesheet(this);
1067
1068    defMatch = new XPath("/", this, this, XPath.MATCH, errorListener);
1069
1070    m_defaultRootRule.setMatch(defMatch);
1071
1072    childrenElement = new ElemApplyTemplates();
1073
1074    childrenElement.setIsDefaultTemplate(true);
1075    m_defaultRootRule.appendChild(childrenElement);
1076    childrenElement.setSelect(m_selectDefault);
1077  }
1078
1079  /**
1080   * This is a generic version of C.A.R Hoare's Quick Sort
1081   * algorithm. This will handle arrays that are already
1082   * sorted, and arrays with duplicate keys. It was lifted from
1083   * the NodeSorter class but should probably be eliminated and replaced
1084   * with a call to Collections.sort when we migrate to Java2.<BR>
1085   *
1086   * If you think of a one dimensional array as going from
1087   * the lowest index on the left to the highest index on the right
1088   * then the parameters to this function are lowest index or
1089   * left and highest index or right. The first time you call
1090   * this function it will be with the parameters 0, a.length - 1.
1091   *
1092   * @param v a vector of ElemTemplateElement elements
1093   * @param lo0 left boundary of partition
1094   * @param hi0 right boundary of partition
1095   *
1096   */

1097
1098  private void QuickSort2(Vector JavaDoc v, int lo0, int hi0)
1099    {
1100      int lo = lo0;
1101      int hi = hi0;
1102
1103      if ( hi0 > lo0)
1104      {
1105        // Arbitrarily establishing partition element as the midpoint of
1106
// the array.
1107
ElemTemplateElement midNode = (ElemTemplateElement) v.elementAt( ( lo0 + hi0 ) / 2 );
1108
1109        // loop through the array until indices cross
1110
while( lo <= hi )
1111        {
1112          // find the first element that is greater than or equal to
1113
// the partition element starting from the left Index.
1114
while( (lo < hi0) && (((ElemTemplateElement) v.elementAt(lo)).compareTo(midNode) < 0) )
1115          {
1116            ++lo;
1117          } // end while
1118

1119          // find an element that is smaller than or equal to
1120
// the partition element starting from the right Index.
1121
while( (hi > lo0) && (((ElemTemplateElement) v.elementAt(hi)).compareTo(midNode) > 0) ) {
1122            --hi;
1123          }
1124
1125          // if the indexes have not crossed, swap
1126
if( lo <= hi )
1127          {
1128            ElemTemplateElement node = (ElemTemplateElement) v.elementAt(lo);
1129            v.setElementAt(v.elementAt(hi), lo);
1130            v.setElementAt(node, hi);
1131
1132            ++lo;
1133            --hi;
1134          }
1135        }
1136
1137        // If the right index has not reached the left side of array
1138
// must now sort the left partition.
1139
if( lo0 < hi )
1140        {
1141          QuickSort2( v, lo0, hi );
1142        }
1143
1144        // If the left index has not reached the right side of array
1145
// must now sort the right partition.
1146
if( lo < hi0 )
1147        {
1148          QuickSort2( v, lo, hi0 );
1149        }
1150      }
1151    } // end QuickSort2 */
1152

1153    private ComposeState m_composeState;
1154    
1155    /**
1156     * Initialize a new ComposeState.
1157     */

1158    void initComposeState()
1159    {
1160      m_composeState = new ComposeState();
1161    }
1162
1163    /**
1164     * Return class to track state global state during the compose() operation.
1165     * @return ComposeState reference, or null if endCompose has been called.
1166     */

1167    ComposeState getComposeState()
1168    {
1169      return m_composeState;
1170    }
1171    
1172    /**
1173     * Clear the compose state.
1174     */

1175    private void clearComposeState()
1176    {
1177      m_composeState = null;
1178    }
1179    
1180    /**
1181     * Class to track state global state during the compose() operation.
1182     */

1183    class ComposeState
1184    {
1185      ComposeState()
1186      {
1187        int size = m_variables.size();
1188        for (int i = 0; i < size; i++)
1189        {
1190          ElemVariable ev = (ElemVariable)m_variables.elementAt(i);
1191          m_variableNames.addElement(ev.getName());
1192        }
1193        
1194      }
1195      
1196      private ExpandedNameTable m_ent = new ExpandedNameTable();
1197      
1198      /**
1199       * Given a qualified name, return an integer ID that can be
1200       * quickly compared.
1201       *
1202       * @param qname a qualified name object, must not be null.
1203       *
1204       * @return the expanded-name id of the qualified name.
1205       */

1206      public int getQNameID(QName qname)
1207      {
1208        
1209        return m_ent.getExpandedTypeID(qname.getNamespace(),
1210                                       qname.getLocalName(),
1211                                       // The type doesn't matter for our
1212
// purposes.
1213
org.apache.xml.dtm.DTM.ELEMENT_NODE);
1214      }
1215      
1216      /**
1217       * A Vector of the current params and QNames within the current template.
1218       * Set by ElemTemplate and used by ProcessorVariable.
1219       */

1220      private java.util.Vector JavaDoc m_variableNames = new java.util.Vector JavaDoc();
1221            
1222      /**
1223       * Add the name of a qualified name within the template. The position in
1224       * the vector is its ID.
1225       * @param qname A qualified name of a param or variable, should be non-null.
1226       * @return the index where the variable was added.
1227       */

1228      int addVariableName(final org.apache.xml.utils.QName qname)
1229      {
1230        int pos = m_variableNames.size();
1231        m_variableNames.addElement(qname);
1232        int frameSize = m_variableNames.size() - getGlobalsSize();
1233        if(frameSize > m_maxStackFrameSize)
1234          m_maxStackFrameSize++;
1235        return pos;
1236      }
1237      
1238      void resetStackFrameSize()
1239      {
1240        m_maxStackFrameSize = 0;
1241      }
1242      
1243      int getFrameSize()
1244      {
1245        return m_maxStackFrameSize;
1246      }
1247      
1248      /**
1249       * Get the current size of the stack frame. Use this to record the position
1250       * in a template element at startElement, so that it can be popped
1251       * at endElement.
1252       */

1253      int getCurrentStackFrameSize()
1254      {
1255        return m_variableNames.size();
1256      }
1257      
1258      /**
1259       * Set the current size of the stack frame.
1260       */

1261      void setCurrentStackFrameSize(int sz)
1262      {
1263        m_variableNames.setSize(sz);
1264      }
1265      
1266      int getGlobalsSize()
1267      {
1268        return m_variables.size();
1269      }
1270      
1271      IntStack m_marks = new IntStack();
1272      
1273      void pushStackMark()
1274      {
1275        m_marks.push(getCurrentStackFrameSize());
1276      }
1277      
1278      void popStackMark()
1279      {
1280        int mark = m_marks.pop();
1281        setCurrentStackFrameSize(mark);
1282      }
1283      
1284      /**
1285       * Get the Vector of the current params and QNames to be collected
1286       * within the current template.
1287       * @return A reference to the vector of variable names. The reference
1288       * returned is owned by this class, and so should not really be mutated, or
1289       * stored anywhere.
1290       */

1291      java.util.Vector JavaDoc getVariableNames()
1292      {
1293        return m_variableNames;
1294      }
1295      
1296      private int m_maxStackFrameSize;
1297
1298    }
1299}
1300
Popular Tags