KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > style > XSLStyleSheet


1 package com.icl.saxon.style;
2 import com.icl.saxon.tree.AttributeCollection;
3 import com.icl.saxon.*;
4 import com.icl.saxon.om.*;
5 import com.icl.saxon.handlers.*;
6 import com.icl.saxon.expr.*;
7 import com.icl.saxon.output.*;
8 import com.icl.saxon.tree.NodeImpl;
9 import com.icl.saxon.trace.*; // e.g.
10
import javax.xml.transform.*;
11
12 import org.xml.sax.Attributes JavaDoc;
13 import java.util.*;
14 import java.io.*;
15
16 /**
17 * An xsl:stylesheet or xsl:transform element in the stylesheet.<BR>
18 * Note this element represents a stylesheet module, not necessarily
19 * the whole stylesheet.
20 */

21
22 public class XSLStyleSheet extends StyleElement {
23
24                 // true if diagnostic trace set
25
//private boolean tracing = false;
26

27                 // true if this stylesheet was included by xsl:include, false if it is the
28
// principal stylesheet or if it was imported
29
private boolean wasIncluded = false;
30
31                 // the import precedence for top-level elements in this stylesheet
32
private int precedence = 0;
33
34                 // the lowest precedence of any stylesheet imported by this one
35
private int minImportPrecedence = 0;
36     
37                 // the StyleSheet that included or imported this one; null for the principal stylesheet
38
private XSLStyleSheet importer = null;
39     
40                 // the PreparedStyleSheet object used to load this stylesheet
41
private PreparedStyleSheet stylesheet;
42     
43                 // the top-level elements in this logical stylesheet (after include/import)
44
private Vector topLevel;
45     
46                 // definitions of strip/preserve space action
47
private Mode stripperRules = null;
48     
49                 // definitions of template rules
50
private RuleManager ruleManager;
51     
52                 // definitions of keys
53
private KeyManager keyManager = new KeyManager();
54     
55                 // definitions of decimal formats
56
private DecimalFormatManager decimalFormatManager = new DecimalFormatManager();
57     
58                 // definitions of preview elements
59
private PreviewManager previewManager = null;
60     
61                 // media type (MIME type) of principal output
62
//private String mediaType;
63

64                 // namespace aliases
65
private int numberOfAliases = 0;
66     private short[] aliasSCodes = new short[5];
67     private short[] aliasRCodes = new short[5];
68
69                 // count of the number of global parameters and variables
70
private int numberOfVariables = 0;
71
72                 // count of the maximum umber of local variables in any template
73
private int largestStackFrame = 0;
74
75
76     /**
77     * Create link to the owning PreparedStyleSheet object
78     */

79
80     public void setPreparedStyleSheet(PreparedStyleSheet sheet) {
81         stylesheet = sheet;
82         ruleManager = new RuleManager(sheet.getNamePool());
83     }
84     
85     /**
86     * Get the owning PreparedStyleSheet object
87     */

88
89     public PreparedStyleSheet getPreparedStyleSheet() {
90         if (importer!=null) return importer.getPreparedStyleSheet();
91         return stylesheet;
92     }
93
94     /**
95     * Get the RuleManager which handles template rules
96     */

97
98     public RuleManager getRuleManager() {
99         return ruleManager;
100     }
101
102     /**
103     * Get the rules determining which nodes are to be stripped from the tree
104     */

105     
106     protected Mode getStripperRules() {
107         if (stripperRules==null) {
108             stripperRules = new Mode();
109         }
110         return stripperRules;
111     }
112
113
114     /**
115     * Create a Stripper which handles whitespace stripping definitions
116     */

117
118     public Stripper newStripper() {
119         return new Stripper(stripperRules);
120     }
121     
122     /**
123     * Determine whether this stylesheet does any whitespace stripping
124     */

125     
126     public boolean stripsWhitespace() {
127         StandardNames sn = getStandardNames();
128         for (int i=0; i<topLevel.size(); i++) {
129             NodeInfo s = (NodeInfo)topLevel.elementAt(i);
130             if (s.getFingerprint()==sn.XSL_STRIP_SPACE) {
131                 return true;
132             }
133         }
134         return false;
135     }
136     
137     /**
138     * Get the KeyManager which handles key definitions
139     */

140     
141     public KeyManager getKeyManager() {
142         return keyManager;
143     }
144
145     /**
146     * Get the DecimalFormatManager which handles decimal-format definitions
147     */

148
149     public DecimalFormatManager getDecimalFormatManager() {
150         return decimalFormatManager;
151     }
152
153     /**
154     * Get the PreviewManager which handles saxon:preview element definitions
155     * @return null if there are no saxon:preview elements
156     */

157
158     public PreviewManager getPreviewManager() {
159         return previewManager;
160     }
161
162     /**
163     * Set the preview manager
164     */

165
166     public void setPreviewManager(PreviewManager pm) {
167         previewManager = pm;
168     }
169
170     /**
171     * Set the import precedence of this stylesheet
172     */

173
174     public void setPrecedence(int prec) {
175         precedence = prec;
176     }
177
178     /**
179     * Get the import precedence of this stylesheet
180     */

181
182     public int getPrecedence() {
183         if (wasIncluded) return importer.getPrecedence();
184         return precedence;
185     }
186
187     /**
188     * Get the minimum import precedence of this stylesheet, that is, the lowest precedence
189     * of any stylesheet imported by this one
190     */

191
192     public int getMinImportPrecedence() {
193         return minImportPrecedence;
194     }
195     
196     /**
197     * Set the minimum import precedence of this stylesheet, that is, the lowest precedence
198     * of any stylesheet imported by this one
199     */

200     
201     public void setMinImportPrecedence(int precedence) {
202         minImportPrecedence = precedence;
203     }
204
205     /**
206     * Set the StyleSheet that included or imported this one.
207     */

208
209     public void setImporter(XSLStyleSheet importer) {
210         this.importer = importer;
211     }
212
213     /**
214     * Get the StyleSheet that included or imported this one.
215     * @return null if this is the principal stylesheet
216     */

217
218     public XSLStyleSheet getImporter() {
219         return importer;
220     }
221
222     /**
223     * Indicate that this stylesheet was included (by its "importer") using an xsl:include
224     * statement as distinct from xsl:import
225     */

226
227     public void setWasIncluded() {
228         wasIncluded = true;
229     }
230
231     /**
232     * Determine whether this stylesheet was included (by its "importer") using an xsl:include
233     * statement as distinct from xsl:import.
234     */

235
236     public boolean wasIncluded() {
237         return wasIncluded;
238     }
239
240     /**
241     * Get the top level elements in this stylesheet, after applying include/import
242     */

243
244     public Vector getTopLevel() {
245         return topLevel;
246     }
247
248     /**
249     * Allocate a slot number for a global variable or parameter
250     */

251
252     public int allocateSlotNumber() {
253         return numberOfVariables++;
254     }
255
256     /**
257     * Ensure there is enuogh space for local variables or parameters in any template
258     */

259
260     public void allocateLocalSlots(int n) {
261         if (n > largestStackFrame) {
262             largestStackFrame = n;
263         }
264     }
265
266     /**
267     * Prepare the attributes on the stylesheet element
268     */

269
270     public void prepareAttributes() throws TransformerConfigurationException {
271
272         StandardNames sn = getStandardNames();
273         AttributeCollection atts = getAttributeList();
274         for (int a=0; a<atts.getLength(); a++) {
275
276             int nc = atts.getNameCode(a);
277             int f = nc & 0xfffff;
278             if (f==sn.VERSION) {
279                 version = atts.getValueByFingerprint(f);
280             } else if (f==sn.ID) {
281                 //
282
} else if (f==sn.EXTENSION_ELEMENT_PREFIXES) {
283                 //
284
} else if (f==sn.EXCLUDE_RESULT_PREFIXES) {
285                 //
286
} else {
287                 checkUnknownAttribute(nc);
288             }
289         }
290         if (version==null) {
291             reportAbsence("version");
292         }
293     }
294
295     /**
296     * Process the version attribute - mandatory on this element (but checked elsewhere)
297     */

298
299     protected void processVersionAttribute(int nc) {
300         version = getAttributeValue(nc & 0xfffff);
301     }
302
303     /**
304     * Get the declared namespace alias for a given namespace URI code if there is one.
305     * If there is more than one, we get the last.
306     * @param uriCode The code of the uri used in the stylesheet.
307     * @return The code of the result uri to be used: return the stylesheet uri unchanged
308     * if no alias is defined
309     */

310
311     protected short getNamespaceAlias(short uriCode) {
312
313         // if there are several matches, the last takes priority
314
for (int i=numberOfAliases-1; i>=0; i--) {
315             if (uriCode==aliasSCodes[i]) {
316                 return aliasRCodes[i];
317             }
318         }
319         return uriCode;
320     }
321
322     /**
323     * Validate this element
324     */

325     
326     public void validate() throws TransformerConfigurationException {
327         if (validationError != null) {
328             compileError(validationError);
329         }
330         if (!(getParentNode() instanceof DocumentInfo)) {
331             throw new TransformerConfigurationException(
332                         getDisplayName() + " must be the outermost element");
333         }
334     }
335
336     /**
337     * Preprocess does all the processing possible before the source document is available.
338     * It is done once per stylesheet, so the stylesheet can be reused for multiple source
339     * documents.
340     */

341
342     public void preprocess() throws TransformerConfigurationException {
343
344         // process any xsl:include and xsl:import elements
345

346         spliceIncludes();
347         
348
349         // process the attributes of every node in the tree
350

351         processAllAttributes();
352
353         // collect any namespace aliases
354

355         collectNamespaceAliases();
356
357         // Validate the whole logical style sheet (i.e. with included and imported sheets)
358

359         validate();
360         for (int i=0; i<topLevel.size(); i++) {
361             Object JavaDoc node = topLevel.elementAt(i);
362             if (node instanceof StyleElement) {
363                 ((StyleElement)node).validateSubtree();
364             }
365         }
366
367         // Preprocess definitions of top-level elements.
368

369         for (int i=0; i<topLevel.size(); i++) {
370             Object JavaDoc s = topLevel.elementAt(i);
371             if (s instanceof StyleElement) {
372                 try {
373                     ((StyleElement)s).preprocess();
374                 } catch (TransformerConfigurationException err) {
375                     ((StyleElement)s).compileError(err);
376                 }
377             }
378         }
379
380     }
381
382     /**
383     * Process xsl:include and xsl:import elements.
384     */

385
386     public void spliceIncludes() throws TransformerConfigurationException {
387
388         boolean foundNonImport = false;
389         topLevel = new Vector();
390         minImportPrecedence = precedence;
391         StyleElement previousElement = this;
392         
393         NodeImpl child = (NodeImpl)getFirstChild();
394         
395         while(child!=null) {
396
397             if (child.getNodeType() == NodeInfo.TEXT) {
398                 // in an embedded stylesheet, white space nodes may still be there
399
if (!Navigator.isWhite(child.getStringValue())) {
400                     previousElement.compileError(
401                         "No character data is allowed between top-level elements");
402                 }
403                 
404             } else {
405                 previousElement = (StyleElement)child;
406                 if (child instanceof XSLGeneralIncorporate) {
407                     XSLGeneralIncorporate xslinc = (XSLGeneralIncorporate)child;
408                     xslinc.processAttributes();
409                 
410                     if (xslinc.isImport()) {
411                         if (foundNonImport) {
412                             xslinc.compileError("xsl:import elements must come first");
413                         }
414                     } else {
415                         foundNonImport = true;
416                     }
417
418                     // get the included stylesheet. This follows the URL, builds a tree, and splices
419
// in any indirectly-included stylesheets.
420

421                     XSLStyleSheet inc =
422                         xslinc.getIncludedStyleSheet(this, precedence);
423                     if (inc==null) return; // error has been reported
424

425                     // after processing the imported stylesheet and any others it brought in,
426
// adjust the import precedence of this stylesheet if necessary
427

428                     if (xslinc.isImport()) {
429                         precedence = inc.getPrecedence() + 1;
430                     } else {
431                         precedence = inc.getPrecedence();
432                         inc.setMinImportPrecedence(minImportPrecedence);
433                         inc.setWasIncluded();
434                     }
435
436                     // copy the top-level elements of the included stylesheet into the top level of this
437
// stylesheet. Normally we add these elements at the end, in order, but if the precedence
438
// of an element is less than the precedence of the previous element, we promote it.
439
// This implements the requirement in the spec that when xsl:include is used to
440
// include a stylesheet, any xsl:import elements in the included document are moved
441
// up in the including document to after any xsl:import elements in the including
442
// document.
443

444                     Vector incchildren = inc.topLevel;
445                     for (int j=0; j<incchildren.size(); j++) {
446                         StyleElement elem = (StyleElement)incchildren.elementAt(j);
447                         int last = topLevel.size() - 1;
448                         if (last < 0 || elem.getPrecedence() >= ((StyleElement)topLevel.elementAt(last)).getPrecedence()) {
449                             topLevel.addElement(elem);
450                         } else {
451                             while (last >=0 && elem.getPrecedence() < ((StyleElement)topLevel.elementAt(last)).getPrecedence()) {
452                                 last--;
453                             }
454                             topLevel.insertElementAt(elem, last+1);
455                         }
456                     }
457                 } else {
458                     foundNonImport = true;
459                     topLevel.addElement(child);
460                 }
461             }
462             child = (NodeImpl)child.getNextSibling();
463         }
464     }
465
466
467     /**
468     * Collect any namespace aliases
469     */

470     
471     private void collectNamespaceAliases() {
472         for (int i=0; i<topLevel.size(); i++) {
473             Object JavaDoc node = topLevel.elementAt(i);
474             if (node instanceof XSLNamespaceAlias) {
475                 XSLNamespaceAlias xna = (XSLNamespaceAlias)node;
476
477                 if (numberOfAliases == aliasSCodes.length) {
478                     short[] s2 = new short[numberOfAliases*2];
479                     short[] r2 = new short[numberOfAliases*2];
480                     System.arraycopy(aliasSCodes, 0, s2, 0, numberOfAliases);
481                     System.arraycopy(aliasRCodes, 0, r2, 0, numberOfAliases);
482                     aliasSCodes = s2;
483                     aliasRCodes = r2;
484                 }
485                 aliasSCodes[numberOfAliases] = xna.getStylesheetURICode();
486                 aliasRCodes[numberOfAliases] = xna.getResultURICode();
487                 numberOfAliases++;
488             }
489         }
490     }
491     
492     protected boolean hasNamespaceAliases() {
493         return numberOfAliases>0;
494     }
495
496     /**
497     * Process the attributes of every node in the stylesheet
498     */

499
500     public void processAllAttributes() throws TransformerConfigurationException {
501         prepareAttributes();
502         Vector children = topLevel;
503         for (int i=0; i<children.size(); i++) {
504             Object JavaDoc s = children.elementAt(i);
505             if (s instanceof StyleElement) {
506                 try {
507                     ((StyleElement)s).processAllAttributes();
508                 } catch (TransformerConfigurationException err) {
509                     ((StyleElement)s).compileError(err);
510                 }
511             }
512         }
513     }
514
515     /**
516     * Allocate space in bindery for all the variables needed
517     * This has to be done early to accommodate preview mode
518     */

519
520     public void initialiseBindery(Bindery bindery) {
521        // ensure enough slots are available for global variables and for the largest stackframe
522

523         bindery.allocateGlobals(numberOfVariables);
524         bindery.allocateLocals(largestStackFrame);
525     }
526
527     /**
528     * Update an output properties object using the xsl:output elements in the stylesheet.
529     * This method can be called before the source document is available; all properties
530     * will be returned as written, with attribute value templates and namespace prefixes
531     * unexpanded, and no validation performed.
532     */

533
534     public void gatherOutputProperties(Properties details) {
535         Vector children = topLevel;
536         for (int i=0; i<children.size(); i++) {
537             Object JavaDoc s = children.elementAt(i);
538             if (s instanceof XSLOutput) {
539                 ((XSLOutput)s).gatherOutputProperties(details);
540             }
541         }
542     }
543
544     /**
545     * Update an output properties object using the xsl:output elements in the stylesheet.
546     * Note, as xsl:output now allows attribute value templates, this cannot be called until
547     * the source document is available.
548     */

549
550     public void updateOutputProperties(Properties details, Context context)
551     throws TransformerException {
552         Vector children = topLevel;
553         for (int i=0; i<children.size(); i++) {
554             Object JavaDoc s = children.elementAt(i);
555             if (s instanceof XSLOutput) {
556                 ((XSLOutput)s).updateOutputProperties(details, context);
557             }
558         }
559     }
560
561     /**
562     * Get a Java class for a given namespace URI, if possible.
563     * return null if none is found.
564     * @throws TransformerException if a class is found but cannot
565     * be loaded
566     */

567     
568     public Class JavaDoc getExternalJavaClass(String JavaDoc uri) throws TransformerException {
569         Vector children = topLevel;
570         if (!((Boolean JavaDoc)getPreparedStyleSheet().getTransformerFactory().
571                 getAttribute(FeatureKeys.ALLOW_EXTERNAL_FUNCTIONS)).booleanValue()) {
572             return null;
573         }
574         for (int i=children.size() - 1; i>=0; i--) {
575             Object JavaDoc s = children.elementAt(i);
576             if (s instanceof XSLScript) {
577                 XSLScript script = (XSLScript)s;
578                 Class JavaDoc c = script.getJavaClass(uri);
579                 if (c != null) {
580                     return c;
581                 }
582             }
583         }
584         return null;
585     }
586
587     /**
588     * Process() is called once the source document is available. It activates those top-level
589     * stylesheet elements that were not dealt with at preprocessing stage, notably
590     * global variables and parameters, and xsl:output elements
591     */

592
593     public void process(Context context) throws TransformerException {
594
595         Controller sourceController = context.getController();
596
597         String JavaDoc traceAtt = getAttributeValue(Namespace.SAXON, "trace");
598         if (traceAtt!=null && traceAtt.equals("yes")) {
599             sourceController.setTraceListener(new com.icl.saxon.trace.SimpleTraceListener());
600         }
601
602         // process all the top-level elements
603

604         Vector children = topLevel;
605
606         boolean tracing = sourceController.isTracing();
607         TraceListener listener = null;
608
609         if (tracing) { // e.g.
610
listener = sourceController.getTraceListener();
611             for (int i=0; i<children.size(); i++) {
612                 Object JavaDoc s = children.elementAt(i);
613                 listener.toplevel((NodeInfo)s);
614             }
615         }
616
617         for (int i=0; i<children.size(); i++) {
618             Object JavaDoc s = children.elementAt(i);
619             if (s instanceof StyleElement) {
620                 try {
621                     if (tracing && !(s instanceof XSLTemplate)) {
622                         listener.enter((StyleElement)s, context);
623                         ((StyleElement)s).process(context);
624                         listener.leave((StyleElement)s, context);
625                     } else {
626                         ((StyleElement)s).process(context);
627                     }
628                 } catch (TransformerException err) {
629                     throw ((StyleElement)s).styleError(err);
630                 }
631             }
632         }
633     }
634
635
636     
637 }
638
639 //
640
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
641
// you may not use this file except in compliance with the License. You may obtain a copy of the
642
// License at http://www.mozilla.org/MPL/
643
//
644
// Software distributed under the License is distributed on an "AS IS" basis,
645
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
646
// See the License for the specific language governing rights and limitations under the License.
647
//
648
// The Original Code is: all this file.
649
//
650
// The Initial Developer of the Original Code is
651
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
652
//
653
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
654
//
655
// Contributor(s):
656
// Portions marked "e.g." are from Edwin Glaser (edwin@pannenleiter.de)
657
//
658
Popular Tags