KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > xsltc > compiler > Stylesheet


1 /*
2  * Copyright 2001-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: Stylesheet.java,v 1.59 2004/02/16 22:24:29 minchau Exp $
18  */

19
20 package org.apache.xalan.xsltc.compiler;
21
22 import java.net.URL JavaDoc;
23 import java.net.MalformedURLException JavaDoc;
24
25 import java.util.Vector JavaDoc;
26 import java.util.Enumeration JavaDoc;
27 import java.util.Hashtable JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Properties JavaDoc;
30 import java.util.StringTokenizer JavaDoc;
31
32 import org.apache.xml.utils.SystemIDResolver;
33 import org.apache.bcel.generic.ANEWARRAY;
34 import org.apache.bcel.generic.BasicType;
35 import org.apache.bcel.generic.ConstantPoolGen;
36 import org.apache.bcel.generic.FieldGen;
37 import org.apache.bcel.generic.GETFIELD;
38 import org.apache.bcel.generic.GETSTATIC;
39 import org.apache.bcel.generic.INVOKEINTERFACE;
40 import org.apache.bcel.generic.INVOKESPECIAL;
41 import org.apache.bcel.generic.INVOKEVIRTUAL;
42 import org.apache.bcel.generic.ISTORE;
43 import org.apache.bcel.generic.InstructionHandle;
44 import org.apache.bcel.generic.InstructionList;
45 import org.apache.bcel.generic.LocalVariableGen;
46 import org.apache.bcel.generic.NEW;
47 import org.apache.bcel.generic.NEWARRAY;
48 import org.apache.bcel.generic.PUSH;
49 import org.apache.bcel.generic.PUTFIELD;
50 import org.apache.bcel.generic.PUTSTATIC;
51 import org.apache.bcel.generic.TargetLostException;
52 import org.apache.bcel.util.InstructionFinder;
53 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
54 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
55 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
56 import org.apache.xalan.xsltc.compiler.util.Type;
57 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
58 import org.apache.xalan.xsltc.compiler.util.Util;
59 import org.apache.xalan.xsltc.runtime.AbstractTranslet;
60 import org.apache.xml.dtm.DTM;
61
62 /**
63  * @author Jacek Ambroziak
64  * @author Santiago Pericas-Geertsen
65  * @author Morten Jorgensen
66  */

67 public final class Stylesheet extends SyntaxTreeNode {
68
69     /**
70      * XSLT version defined in the stylesheet.
71      */

72     private String JavaDoc _version;
73     
74     /**
75      * Internal name of this stylesheet used as a key into the symbol table.
76      */

77     private QName _name;
78     
79     /**
80      * A URI that represents the system ID for this stylesheet.
81      */

82     private String JavaDoc _systemId;
83     
84     /**
85      * A reference to the parent stylesheet or null if topmost.
86      */

87     private Stylesheet _parentStylesheet;
88     
89     /**
90      * Contains global variables and parameters defined in the stylesheet.
91      */

92     private Vector JavaDoc _globals = new Vector JavaDoc();
93
94     /**
95      * Used to cache the result returned by <code>hasLocalParams()</code>.
96      */

97     private Boolean JavaDoc _hasLocalParams = null;
98
99     /**
100      * The name of the class being generated.
101      */

102     private String JavaDoc _className;
103     
104     /**
105       * Contains all templates defined in this stylesheet
106       */

107     private final Vector JavaDoc _templates = new Vector JavaDoc();
108     
109     /**
110      * Used to cache result of <code>getAllValidTemplates()</code>. Only
111      * set in top-level stylesheets that include/import other stylesheets.
112      */

113     private Vector JavaDoc _allValidTemplates = null;
114
115     /**
116      * Counter to generate unique mode suffixes.
117      */

118     private int _nextModeSerial = 1;
119     
120     /**
121      * Mapping between mode names and Mode instances.
122      */

123     private final Hashtable JavaDoc _modes = new Hashtable JavaDoc();
124     
125     /**
126      * A reference to the default Mode object.
127      */

128     private Mode _defaultMode;
129
130     /**
131      * Mapping between extension URIs and their prefixes.
132      */

133     private final Hashtable JavaDoc _extensions = new Hashtable JavaDoc();
134
135     /**
136      * Reference to the stylesheet from which this stylesheet was
137      * imported (if any).
138      */

139     public Stylesheet _importedFrom = null;
140     
141     /**
142      * Reference to the stylesheet from which this stylesheet was
143      * included (if any).
144      */

145     public Stylesheet _includedFrom = null;
146     
147     /**
148      * Array of all the stylesheets imported or included from this one.
149      */

150     private Vector JavaDoc _includedStylesheets = null;
151     
152     /**
153      * Import precendence for this stylesheet.
154      */

155     private int _importPrecedence = 1;
156     
157     /**
158      * Mapping between key names and Key objects (needed by Key/IdPattern).
159      */

160     private Hashtable JavaDoc _keys = new Hashtable JavaDoc();
161
162     /**
163      * A reference to the SourceLoader set by the user (a URIResolver
164      * if the JAXP API is being used).
165      */

166     private SourceLoader _loader = null;
167
168     /**
169      * Flag indicating if format-number() is called.
170      */

171     private boolean _numberFormattingUsed = false;
172
173     /**
174      * Flag indicating if this is a simplified stylesheets. A template
175      * matching on "/" must be added in this case.
176      */

177     private boolean _simplified = false;
178
179     /**
180      * Flag indicating if multi-document support is needed.
181      */

182     private boolean _multiDocument = false;
183     
184     /**
185      * Flag indicating if nodset() is called.
186      */

187     private boolean _callsNodeset = false;
188
189     /**
190      * Flag indicating if id() is called.
191      */

192     private boolean _hasIdCall = false;
193     
194     /**
195      * Set to true to enable template inlining optimization.
196      */

197     private boolean _templateInlining = true;
198
199     /**
200      * A reference to the last xsl:output object found in the styleshet.
201      */

202     private Output _lastOutputElement = null;
203     
204     /**
205      * Output properties for this stylesheet.
206      */

207     private Properties JavaDoc _outputProperties = null;
208     
209     /**
210      * Output method for this stylesheet (must be set to one of
211      * the constants defined below).
212      */

213     private int _outputMethod = UNKNOWN_OUTPUT;
214
215     // Output method constants
216
public static final int UNKNOWN_OUTPUT = 0;
217     public static final int XML_OUTPUT = 1;
218     public static final int HTML_OUTPUT = 2;
219     public static final int TEXT_OUTPUT = 3;
220     
221     /**
222      * Return the output method
223      */

224     public int getOutputMethod() {
225         return _outputMethod;
226     }
227     
228     /**
229      * Check and set the output method
230      */

231     private void checkOutputMethod() {
232     if (_lastOutputElement != null) {
233         String JavaDoc method = _lastOutputElement.getOutputMethod();
234         if (method != null) {
235             if (method.equals("xml"))
236                 _outputMethod = XML_OUTPUT;
237             else if (method.equals("html"))
238                 _outputMethod = HTML_OUTPUT;
239             else if (method.equals("text"))
240                 _outputMethod = TEXT_OUTPUT;
241         }
242     }
243     }
244
245     public boolean getTemplateInlining() {
246     return _templateInlining;
247     }
248
249     public void setTemplateInlining(boolean flag) {
250     _templateInlining = flag;
251     }
252
253     public boolean isSimplified() {
254     return(_simplified);
255     }
256
257     public void setSimplified() {
258     _simplified = true;
259     }
260     
261     public void setHasIdCall(boolean flag) {
262         _hasIdCall = flag;
263     }
264     
265     public void setOutputProperty(String JavaDoc key, String JavaDoc value) {
266     if (_outputProperties == null) {
267         _outputProperties = new Properties JavaDoc();
268     }
269     _outputProperties.setProperty(key, value);
270     }
271
272     public void setOutputProperties(Properties JavaDoc props) {
273     _outputProperties = props;
274     }
275
276     public Properties JavaDoc getOutputProperties() {
277     return _outputProperties;
278     }
279
280     public Output getLastOutputElement() {
281         return _lastOutputElement;
282     }
283     
284     public void setMultiDocument(boolean flag) {
285     _multiDocument = flag;
286     }
287
288     public boolean isMultiDocument() {
289     return _multiDocument;
290     }
291
292     public void setCallsNodeset(boolean flag) {
293     if (flag) setMultiDocument(flag);
294     _callsNodeset = flag;
295     }
296
297     public boolean callsNodeset() {
298     return _callsNodeset;
299     }
300
301     public void numberFormattingUsed() {
302     _numberFormattingUsed = true;
303         /*
304          * Fix for bug 23046, if the stylesheet is included, set the
305          * numberFormattingUsed flag to the parent stylesheet too.
306          * AbstractTranslet.addDecimalFormat() will be inlined once for the
307          * outer most stylesheet.
308          */

309         Stylesheet parent = getParentStylesheet();
310         if (null != parent) parent.numberFormattingUsed();
311     }
312
313     public void setImportPrecedence(final int precedence) {
314     // Set import precedence for this stylesheet
315
_importPrecedence = precedence;
316
317     // Set import precedence for all included stylesheets
318
final Enumeration JavaDoc elements = elements();
319     while (elements.hasMoreElements()) {
320         SyntaxTreeNode child = (SyntaxTreeNode)elements.nextElement();
321         if (child instanceof Include) {
322         Stylesheet included = ((Include)child).getIncludedStylesheet();
323         if (included != null && included._includedFrom == this) {
324             included.setImportPrecedence(precedence);
325         }
326         }
327     }
328
329     // Set import precedence for the stylesheet that imported this one
330
if (_importedFrom != null) {
331         if (_importedFrom.getImportPrecedence() < precedence) {
332         final Parser parser = getParser();
333         final int nextPrecedence = parser.getNextImportPrecedence();
334         _importedFrom.setImportPrecedence(nextPrecedence);
335         }
336     }
337     // Set import precedence for the stylesheet that included this one
338
else if (_includedFrom != null) {
339         if (_includedFrom.getImportPrecedence() != precedence)
340         _includedFrom.setImportPrecedence(precedence);
341     }
342     }
343     
344     public int getImportPrecedence() {
345     return _importPrecedence;
346     }
347
348     public boolean checkForLoop(String JavaDoc systemId) {
349     // Return true if this stylesheet includes/imports itself
350
if (_systemId != null && _systemId.equals(systemId)) {
351         return true;
352     }
353     // Then check with any stylesheets that included/imported this one
354
if (_parentStylesheet != null)
355         return _parentStylesheet.checkForLoop(systemId);
356     // Otherwise OK
357
return false;
358     }
359     
360     public void setParser(Parser parser) {
361     super.setParser(parser);
362     _name = makeStylesheetName("__stylesheet_");
363     }
364     
365     public void setParentStylesheet(Stylesheet parent) {
366     _parentStylesheet = parent;
367     }
368     
369     public Stylesheet getParentStylesheet() {
370     return _parentStylesheet;
371     }
372
373     public void setImportingStylesheet(Stylesheet parent) {
374     _importedFrom = parent;
375     parent.addIncludedStylesheet(this);
376     }
377
378     public void setIncludingStylesheet(Stylesheet parent) {
379     _includedFrom = parent;
380     parent.addIncludedStylesheet(this);
381     }
382
383     public void addIncludedStylesheet(Stylesheet child) {
384         if (_includedStylesheets == null) {
385             _includedStylesheets = new Vector JavaDoc();
386         }
387         _includedStylesheets.addElement(child);
388     }
389
390     public void setSystemId(String JavaDoc systemId) {
391         if (systemId != null) {
392             _systemId = SystemIDResolver.getAbsoluteURI(systemId);
393         }
394     }
395     
396     public String JavaDoc getSystemId() {
397     return _systemId;
398     }
399
400     public void setSourceLoader(SourceLoader loader) {
401     _loader = loader;
402     }
403     
404     public SourceLoader getSourceLoader() {
405     return _loader;
406     }
407
408     private QName makeStylesheetName(String JavaDoc prefix) {
409     return getParser().getQName(prefix+getXSLTC().nextStylesheetSerial());
410     }
411
412     /**
413      * Returns true if this stylesheet has global vars or params.
414      */

415     public boolean hasGlobals() {
416     return _globals.size() > 0;
417     }
418
419     /**
420      * Returns true if at least one template in the stylesheet has params
421      * defined. Uses the variable <code>_hasLocalParams</code> to cache the
422      * result.
423      */

424     public boolean hasLocalParams() {
425     if (_hasLocalParams == null) {
426         Vector JavaDoc templates = getAllValidTemplates();
427         final int n = templates.size();
428         for (int i = 0; i < n; i++) {
429         final Template template = (Template)templates.elementAt(i);
430         if (template.hasParams()) {
431             _hasLocalParams = new Boolean JavaDoc(true);
432             return true;
433         }
434         }
435         _hasLocalParams = new Boolean JavaDoc(false);
436         return false;
437     }
438     else {
439         return _hasLocalParams.booleanValue();
440     }
441     }
442
443     /**
444      * Adds a single prefix mapping to this syntax tree node.
445      * @param prefix Namespace prefix.
446      * @param uri Namespace URI.
447      */

448     protected void addPrefixMapping(String JavaDoc prefix, String JavaDoc uri) {
449     if (prefix.equals(EMPTYSTRING) && uri.equals(XHTML_URI)) return;
450     super.addPrefixMapping(prefix, uri);
451     }
452
453     /**
454      * Store extension URIs
455      */

456     private void extensionURI(String JavaDoc prefixes, SymbolTable stable) {
457     if (prefixes != null) {
458         StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(prefixes);
459         while (tokens.hasMoreTokens()) {
460         final String JavaDoc prefix = tokens.nextToken();
461         final String JavaDoc uri = lookupNamespace(prefix);
462         if (uri != null) {
463             _extensions.put(uri, prefix);
464         }
465         }
466     }
467     }
468
469     public boolean isExtension(String JavaDoc uri) {
470     return (_extensions.get(uri) != null);
471     }
472
473     public void excludeExtensionPrefixes(Parser parser) {
474     final SymbolTable stable = parser.getSymbolTable();
475         final String JavaDoc excludePrefixes = getAttribute("exclude-result-prefixes");
476     final String JavaDoc extensionPrefixes = getAttribute("extension-element-prefixes");
477     
478     // Exclude XSLT uri
479
stable.excludeURI(Constants.XSLT_URI);
480     stable.excludeNamespaces(excludePrefixes);
481     stable.excludeNamespaces(extensionPrefixes);
482     extensionURI(extensionPrefixes, stable);
483     }
484
485     /**
486      * Parse the version and uri fields of the stylesheet and add an
487      * entry to the symbol table mapping the name <tt>__stylesheet_</tt>
488      * to an instance of this class.
489      */

490     public void parseContents(Parser parser) {
491     final SymbolTable stable = parser.getSymbolTable();
492
493     /*
494     // Make sure the XSL version set in this stylesheet
495     if ((_version == null) || (_version.equals(EMPTYSTRING))) {
496         reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR,"version");
497     }
498     // Verify that the version is 1.0 and nothing else
499     else if (!_version.equals("1.0")) {
500         reportError(this, parser, ErrorMsg.XSL_VERSION_ERR, _version);
501     }
502     */

503
504     // Add the implicit mapping of 'xml' to the XML namespace URI
505
addPrefixMapping("xml", "http://www.w3.org/XML/1998/namespace");
506
507     // Report and error if more than one stylesheet defined
508
final Stylesheet sheet = stable.addStylesheet(_name, this);
509     if (sheet != null) {
510         // Error: more that one stylesheet defined
511
ErrorMsg err = new ErrorMsg(ErrorMsg.MULTIPLE_STYLESHEET_ERR,this);
512         parser.reportError(Constants.ERROR, err);
513     }
514
515     // If this is a simplified stylesheet we must create a template that
516
// grabs the root node of the input doc ( <xsl:template match="/"/> ).
517
// This template needs the current element (the one passed to this
518
// method) as its only child, so the Template class has a special
519
// method that handles this (parseSimplified()).
520
if (_simplified) {
521         stable.excludeURI(XSLT_URI);
522         Template template = new Template();
523         template.parseSimplified(this, parser);
524     }
525     // Parse the children of this node
526
else {
527         parseOwnChildren(parser);
528     }
529     }
530
531     /**
532      * Parse all direct children of the <xsl:stylesheet/> element.
533      */

534     public final void parseOwnChildren(Parser parser) {
535     final Vector JavaDoc contents = getContents();
536     final int count = contents.size();
537
538     // We have to scan the stylesheet element's top-level elements for
539
// variables and/or parameters before we parse the other elements
540
for (int i = 0; i < count; i++) {
541         SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
542         if ((child instanceof VariableBase) ||
543         (child instanceof NamespaceAlias)) {
544         parser.getSymbolTable().setCurrentNode(child);
545         child.parseContents(parser);
546         }
547     }
548
549     // Now go through all the other top-level elements...
550
for (int i = 0; i < count; i++) {
551         SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
552         if (!(child instanceof VariableBase) &&
553         !(child instanceof NamespaceAlias)) {
554         parser.getSymbolTable().setCurrentNode(child);
555         child.parseContents(parser);
556         }
557
558         // All template code should be compiled as methods if the
559
// <xsl:apply-imports/> element was ever used in this stylesheet
560
if (!_templateInlining && (child instanceof Template)) {
561         Template template = (Template)child;
562         String JavaDoc name = "template$dot$" + template.getPosition();
563         template.setName(parser.getQName(name));
564         }
565     }
566     }
567
568     public void processModes() {
569     if (_defaultMode == null)
570         _defaultMode = new Mode(null, this, Constants.EMPTYSTRING);
571     _defaultMode.processPatterns(_keys);
572     final Enumeration JavaDoc modes = _modes.elements();
573     while (modes.hasMoreElements()) {
574         final Mode mode = (Mode)modes.nextElement();
575         mode.processPatterns(_keys);
576     }
577     }
578     
579     private void compileModes(ClassGenerator classGen) {
580     _defaultMode.compileApplyTemplates(classGen);
581     final Enumeration JavaDoc modes = _modes.elements();
582     while (modes.hasMoreElements()) {
583         final Mode mode = (Mode)modes.nextElement();
584         mode.compileApplyTemplates(classGen);
585     }
586     }
587
588     public Mode getMode(QName modeName) {
589     if (modeName == null) {
590         if (_defaultMode == null) {
591         _defaultMode = new Mode(null, this, Constants.EMPTYSTRING);
592         }
593         return _defaultMode;
594     }
595     else {
596         Mode mode = (Mode)_modes.get(modeName);
597         if (mode == null) {
598         final String JavaDoc suffix = Integer.toString(_nextModeSerial++);
599         _modes.put(modeName, mode = new Mode(modeName, this, suffix));
600         }
601         return mode;
602     }
603     }
604
605     /**
606      * Type check all the children of this node.
607      */

608     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
609     final int count = _globals.size();
610     for (int i = 0; i < count; i++) {
611         final VariableBase var = (VariableBase)_globals.elementAt(i);
612         var.typeCheck(stable);
613     }
614     return typeCheckContents(stable);
615     }
616
617     /**
618      * Translate the stylesheet into JVM bytecodes.
619      */

620     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
621     translate();
622     }
623
624     private void addDOMField(ClassGenerator classGen) {
625     final FieldGen fgen = new FieldGen(ACC_PUBLIC,
626                        Util.getJCRefType(DOM_INTF_SIG),
627                        DOM_FIELD,
628                        classGen.getConstantPool());
629     classGen.addField(fgen.getField());
630     }
631     
632     /**
633      * Add a static field
634      */

635     private void addStaticField(ClassGenerator classGen, String JavaDoc type,
636                                 String JavaDoc name)
637     {
638         final FieldGen fgen = new FieldGen(ACC_PROTECTED|ACC_STATIC,
639                                            Util.getJCRefType(type),
640                                            name,
641                                            classGen.getConstantPool());
642         classGen.addField(fgen.getField());
643
644     }
645
646     /**
647      * Translate the stylesheet into JVM bytecodes.
648      */

649     public void translate() {
650     _className = getXSLTC().getClassName();
651
652     // Define a new class by extending TRANSLET_CLASS
653
final ClassGenerator classGen =
654         new ClassGenerator(_className,
655                    TRANSLET_CLASS,
656                    Constants.EMPTYSTRING,
657                    ACC_PUBLIC | ACC_SUPER,
658                    null, this);
659     
660     addDOMField(classGen);
661
662     // Compile transform() to initialize parameters, globals & output
663
// and run the transformation
664
compileTransform(classGen);
665
666     // Translate all non-template elements and filter out all templates
667
final Enumeration JavaDoc elements = elements();
668     while (elements.hasMoreElements()) {
669         Object JavaDoc element = elements.nextElement();
670         // xsl:template
671
if (element instanceof Template) {
672         // Separate templates by modes
673
final Template template = (Template)element;
674         //_templates.addElement(template);
675
getMode(template.getModeName()).addTemplate(template);
676         }
677         // xsl:attribute-set
678
else if (element instanceof AttributeSet) {
679         ((AttributeSet)element).translate(classGen, null);
680         }
681         else if (element instanceof Output) {
682         // save the element for later to pass to compileConstructor
683
Output output = (Output)element;
684         if (output.enabled()) _lastOutputElement = output;
685         }
686         else {
687         // Global variables and parameters are handled elsewhere.
688
// Other top-level non-template elements are ignored. Literal
689
// elements outside of templates will never be output.
690
}
691     }
692
693     checkOutputMethod();
694     processModes();
695     compileModes(classGen);
696         compileStaticInitializer(classGen);
697     compileConstructor(classGen, _lastOutputElement);
698
699     if (!getParser().errorsFound()) {
700         getXSLTC().dumpClass(classGen.getJavaClass());
701     }
702     }
703
704     /**
705      * Compile the namesArray, urisArray and typesArray into
706      * the static initializer. They are read-only from the
707      * translet. All translet instances can share a single
708      * copy of this informtion.
709      */

710     private void compileStaticInitializer(ClassGenerator classGen) {
711     final ConstantPoolGen cpg = classGen.getConstantPool();
712     final InstructionList il = new InstructionList();
713
714     final MethodGenerator staticConst =
715         new MethodGenerator(ACC_PUBLIC|ACC_STATIC,
716                 org.apache.bcel.generic.Type.VOID,
717                 null, null, "<clinit>",
718                 _className, il, cpg);
719
720     addStaticField(classGen, "[" + STRING_SIG, STATIC_NAMES_ARRAY_FIELD);
721     addStaticField(classGen, "[" + STRING_SIG, STATIC_URIS_ARRAY_FIELD);
722     addStaticField(classGen, "[I", STATIC_TYPES_ARRAY_FIELD);
723     addStaticField(classGen, "[" + STRING_SIG, STATIC_NAMESPACE_ARRAY_FIELD);
724         // Create fields of type char[] that will contain literal text from
725
// the stylesheet.
726
final int charDataFieldCount = getXSLTC().getCharacterDataCount();
727         for (int i = 0; i < charDataFieldCount; i++) {
728             addStaticField(classGen, STATIC_CHAR_DATA_FIELD_SIG,
729                            STATIC_CHAR_DATA_FIELD+i);
730         }
731
732     // Put the names array into the translet - used for dom/translet mapping
733
final Vector JavaDoc namesIndex = getXSLTC().getNamesIndex();
734     int size = namesIndex.size();
735     String JavaDoc[] namesArray = new String JavaDoc[size];
736     String JavaDoc[] urisArray = new String JavaDoc[size];
737     int[] typesArray = new int[size];
738     
739     int index;
740     for (int i = 0; i < size; i++) {
741         String JavaDoc encodedName = (String JavaDoc)namesIndex.elementAt(i);
742         if ((index = encodedName.lastIndexOf(':')) > -1) {
743             urisArray[i] = encodedName.substring(0, index);
744         }
745         
746         index = index + 1;
747         if (encodedName.charAt(index) == '@') {
748             typesArray[i] = DTM.ATTRIBUTE_NODE;
749             index++;
750         } else if (encodedName.charAt(index) == '?') {
751             typesArray[i] = DTM.NAMESPACE_NODE;
752             index++;
753         } else {
754             typesArray[i] = DTM.ELEMENT_NODE;
755         }
756         
757         if (index == 0) {
758             namesArray[i] = encodedName;
759         }
760         else {
761             namesArray[i] = encodedName.substring(index);
762         }
763     }
764     
765     il.append(new PUSH(cpg, size));
766     il.append(new ANEWARRAY(cpg.addClass(STRING)));
767
768     for (int i = 0; i < size; i++) {
769         final String JavaDoc name = namesArray[i];
770         il.append(DUP);
771         il.append(new PUSH(cpg, i));
772         il.append(new PUSH(cpg, name));
773         il.append(AASTORE);
774     }
775     il.append(new PUTSTATIC(cpg.addFieldref(_className,
776                            STATIC_NAMES_ARRAY_FIELD,
777                            NAMES_INDEX_SIG)));
778
779     il.append(new PUSH(cpg, size));
780     il.append(new ANEWARRAY(cpg.addClass(STRING)));
781
782     for (int i = 0; i < size; i++) {
783         final String JavaDoc uri = urisArray[i];
784         il.append(DUP);
785         il.append(new PUSH(cpg, i));
786         il.append(new PUSH(cpg, uri));
787         il.append(AASTORE);
788     }
789     il.append(new PUTSTATIC(cpg.addFieldref(_className,
790                            STATIC_URIS_ARRAY_FIELD,
791                            URIS_INDEX_SIG)));
792
793     il.append(new PUSH(cpg, size));
794     il.append(new NEWARRAY(BasicType.INT));
795
796     for (int i = 0; i < size; i++) {
797         final int nodeType = typesArray[i];
798         il.append(DUP);
799         il.append(new PUSH(cpg, i));
800         il.append(new PUSH(cpg, nodeType));
801         il.append(IASTORE);
802     }
803     il.append(new PUTSTATIC(cpg.addFieldref(_className,
804                            STATIC_TYPES_ARRAY_FIELD,
805                            TYPES_INDEX_SIG)));
806
807     // Put the namespace names array into the translet
808
final Vector JavaDoc namespaces = getXSLTC().getNamespaceIndex();
809     il.append(new PUSH(cpg, namespaces.size()));
810     il.append(new ANEWARRAY(cpg.addClass(STRING)));
811
812     for (int i = 0; i < namespaces.size(); i++) {
813         final String JavaDoc ns = (String JavaDoc)namespaces.elementAt(i);
814         il.append(DUP);
815         il.append(new PUSH(cpg, i));
816         il.append(new PUSH(cpg, ns));
817         il.append(AASTORE);
818     }
819     il.append(new PUTSTATIC(cpg.addFieldref(_className,
820                            STATIC_NAMESPACE_ARRAY_FIELD,
821                            NAMESPACE_INDEX_SIG)));
822
823         // Grab all the literal text in the stylesheet and put it in a char[]
824
final int charDataCount = getXSLTC().getCharacterDataCount();
825         final int toCharArray = cpg.addMethodref(STRING, "toCharArray", "()[C");
826         for (int i = 0; i < charDataCount; i++) {
827             il.append(new PUSH(cpg, getXSLTC().getCharacterData(i)));
828             il.append(new INVOKEVIRTUAL(toCharArray));
829             il.append(new PUTSTATIC(cpg.addFieldref(_className,
830                                                STATIC_CHAR_DATA_FIELD+i,
831                                                STATIC_CHAR_DATA_FIELD_SIG)));
832         }
833
834     il.append(RETURN);
835
836     staticConst.stripAttributes(true);
837     staticConst.setMaxLocals();
838     staticConst.setMaxStack();
839     classGen.addMethod(staticConst.getMethod());
840         
841     }
842
843     /**
844      * Compile the translet's constructor
845      */

846     private void compileConstructor(ClassGenerator classGen, Output output) {
847
848     final ConstantPoolGen cpg = classGen.getConstantPool();
849     final InstructionList il = new InstructionList();
850
851     final MethodGenerator constructor =
852         new MethodGenerator(ACC_PUBLIC,
853                 org.apache.bcel.generic.Type.VOID,
854                 null, null, "<init>",
855                 _className, il, cpg);
856
857     // Call the constructor in the AbstractTranslet superclass
858
il.append(classGen.loadTranslet());
859     il.append(new INVOKESPECIAL(cpg.addMethodref(TRANSLET_CLASS,
860                              "<init>", "()V")));
861     
862     il.append(classGen.loadTranslet());
863     il.append(new GETSTATIC(cpg.addFieldref(_className,
864                                             STATIC_NAMES_ARRAY_FIELD,
865                                             NAMES_INDEX_SIG)));
866     il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
867                                            NAMES_INDEX,
868                                            NAMES_INDEX_SIG)));
869     
870     il.append(classGen.loadTranslet());
871     il.append(new GETSTATIC(cpg.addFieldref(_className,
872                                             STATIC_URIS_ARRAY_FIELD,
873                                             URIS_INDEX_SIG)));
874     il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
875                                            URIS_INDEX,
876                                            URIS_INDEX_SIG)));
877
878     il.append(classGen.loadTranslet());
879     il.append(new GETSTATIC(cpg.addFieldref(_className,
880                                             STATIC_TYPES_ARRAY_FIELD,
881                                             TYPES_INDEX_SIG)));
882     il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
883                                            TYPES_INDEX,
884                                            TYPES_INDEX_SIG)));
885
886     il.append(classGen.loadTranslet());
887     il.append(new GETSTATIC(cpg.addFieldref(_className,
888                                             STATIC_NAMESPACE_ARRAY_FIELD,
889                                             NAMESPACE_INDEX_SIG)));
890     il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
891                                            NAMESPACE_INDEX,
892                                            NAMESPACE_INDEX_SIG)));
893
894     il.append(classGen.loadTranslet());
895         il.append(new PUSH(cpg, AbstractTranslet.CURRENT_TRANSLET_VERSION));
896     il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
897                                            TRANSLET_VERSION_INDEX,
898                                            TRANSLET_VERSION_INDEX_SIG)));
899     
900     if (_hasIdCall) {
901         il.append(classGen.loadTranslet());
902         il.append(new PUSH(cpg, Boolean.TRUE));
903         il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
904                                HASIDCALL_INDEX,
905                                HASIDCALL_INDEX_SIG)));
906     }
907     
908     // Compile in code to set the output configuration from <xsl:output>
909
if (output != null) {
910         // Set all the output settings files in the translet
911
output.translate(classGen, constructor);
912     }
913
914     // Compile default decimal formatting symbols.
915
// This is an implicit, nameless xsl:decimal-format top-level element.
916
if (_numberFormattingUsed)
917         DecimalFormatting.translateDefaultDFS(classGen, constructor);
918
919     il.append(RETURN);
920
921     constructor.stripAttributes(true);
922     constructor.setMaxLocals();
923     constructor.setMaxStack();
924     classGen.addMethod(constructor.getMethod());
925     }
926
927     /**
928      * Compile a topLevel() method into the output class. This method is
929      * called from transform() to handle all non-template top-level elemtents.
930      * Returns the signature of the topLevel() method.
931      */

932     private String JavaDoc compileTopLevel(ClassGenerator classGen,
933                    Enumeration JavaDoc elements) {
934
935     final ConstantPoolGen cpg = classGen.getConstantPool();
936
937     final org.apache.bcel.generic.Type[] argTypes = {
938         Util.getJCRefType(DOM_INTF_SIG),
939         Util.getJCRefType(NODE_ITERATOR_SIG),
940         Util.getJCRefType(TRANSLET_OUTPUT_SIG)
941     };
942
943     final String JavaDoc[] argNames = {
944         DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME
945     };
946
947     final InstructionList il = new InstructionList();
948
949     final MethodGenerator toplevel =
950         new MethodGenerator(ACC_PUBLIC,
951                 org.apache.bcel.generic.Type.VOID,
952                 argTypes, argNames,
953                 "topLevel", _className, il,
954                 classGen.getConstantPool());
955
956     toplevel.addException("org.apache.xalan.xsltc.TransletException");
957
958     // Define and initialize 'current' variable with the root node
959
final LocalVariableGen current =
960         toplevel.addLocalVariable("current",
961                     org.apache.bcel.generic.Type.INT,
962                     il.getEnd(), null);
963
964     final int setFilter = cpg.addInterfaceMethodref(DOM_INTF,
965                    "setFilter",
966                    "(Lorg/apache/xalan/xsltc/StripFilter;)V");
967
968     il.append(new PUSH(cpg, DTM.ROOT_NODE));
969     il.append(new ISTORE(current.getIndex()));
970
971     // Resolve any forward referenes and translate global variables/params
972
_globals = resolveReferences(_globals);
973     final int count = _globals.size();
974     for (int i = 0; i < count; i++) {
975         final VariableBase var = (VariableBase)_globals.elementAt(i);
976         var.translate(classGen,toplevel);
977     }
978
979     // Compile code for other top-level elements
980
Vector JavaDoc whitespaceRules = new Vector JavaDoc();
981     while (elements.hasMoreElements()) {
982         final Object JavaDoc element = elements.nextElement();
983         // xsl:decimal-format
984
if (element instanceof DecimalFormatting) {
985         ((DecimalFormatting)element).translate(classGen,toplevel);
986         }
987         // xsl:strip/preserve-space
988
else if (element instanceof Whitespace) {
989         whitespaceRules.addAll(((Whitespace)element).getRules());
990         }
991     }
992
993     // Translate all whitespace strip/preserve rules
994
if (whitespaceRules.size() > 0) {
995         Whitespace.translateRules(whitespaceRules,classGen);
996     }
997
998     if (classGen.containsMethod(STRIP_SPACE, STRIP_SPACE_PARAMS) != null) {
999         il.append(toplevel.loadDOM());
1000        il.append(classGen.loadTranslet());
1001        il.append(new INVOKEINTERFACE(setFilter, 2));
1002    }
1003
1004    il.append(RETURN);
1005
1006    // Compute max locals + stack and add method to class
1007
toplevel.stripAttributes(true);
1008    toplevel.setMaxLocals();
1009    toplevel.setMaxStack();
1010    toplevel.removeNOPs();
1011
1012    classGen.addMethod(toplevel.getMethod());
1013    
1014    return("("+DOM_INTF_SIG+NODE_ITERATOR_SIG+TRANSLET_OUTPUT_SIG+")V");
1015    }
1016
1017    /**
1018     * This method returns a vector with variables in the order in
1019     * which they are to be compiled. The order is determined by the
1020     * dependencies between them and the order in which they were defined
1021     * in the stylesheet. The first step is to close the input vector under
1022     * the dependence relation (this is usually needed when variables are
1023     * defined inside other variables in a RTF).
1024     */

1025    private Vector JavaDoc resolveReferences(Vector JavaDoc input) {
1026
1027    // Make sure that the vector 'input' is closed
1028
for (int i = 0; i < input.size(); i++) {
1029        final VariableBase var = (VariableBase) input.elementAt(i);
1030        final Vector JavaDoc dep = var.getDependencies();
1031        final int depSize = (dep != null) ? dep.size() : 0;
1032
1033        for (int j = 0; j < depSize; j++) {
1034        final VariableBase depVar = (VariableBase) dep.elementAt(j);
1035        if (!input.contains(depVar)) {
1036            input.addElement(depVar);
1037        }
1038        }
1039    }
1040
1041    /* DEBUG CODE - INGORE
1042    for (int i = 0; i < input.size(); i++) {
1043        final VariableBase var = (VariableBase) input.elementAt(i);
1044        System.out.println("var = " + var);
1045    }
1046    System.out.println("=================================");
1047    */

1048
1049    Vector JavaDoc result = new Vector JavaDoc();
1050    while (input.size() > 0) {
1051        boolean changed = false;
1052        for (int i = 0; i < input.size(); ) {
1053        final VariableBase var = (VariableBase)input.elementAt(i);
1054        final Vector JavaDoc dep = var.getDependencies();
1055        if (dep == null || result.containsAll(dep)) {
1056            result.addElement(var);
1057            input.remove(i);
1058            changed = true;
1059        }
1060        else {
1061            i++;
1062        }
1063        }
1064
1065        // If nothing was changed in this pass then we have a circular ref
1066
if (!changed) {
1067        ErrorMsg err = new ErrorMsg(ErrorMsg.CIRCULAR_VARIABLE_ERR,
1068                        input.toString(), this);
1069        getParser().reportError(Constants.ERROR, err);
1070        return(result);
1071        }
1072    }
1073
1074    /* DEBUG CODE - INGORE
1075    System.out.println("=================================");
1076    for (int i = 0; i < result.size(); i++) {
1077        final VariableBase var = (VariableBase) result.elementAt(i);
1078        System.out.println("var = " + var);
1079    }
1080    */

1081
1082    return result;
1083    }
1084
1085    /**
1086     * Compile a buildKeys() method into the output class. This method is
1087     * called from transform() to handle build all indexes needed by key().
1088     */

1089    private String JavaDoc compileBuildKeys(ClassGenerator classGen) {
1090
1091    final ConstantPoolGen cpg = classGen.getConstantPool();
1092
1093    final org.apache.bcel.generic.Type[] argTypes = {
1094        Util.getJCRefType(DOM_INTF_SIG),
1095        Util.getJCRefType(NODE_ITERATOR_SIG),
1096        Util.getJCRefType(TRANSLET_OUTPUT_SIG),
1097        org.apache.bcel.generic.Type.INT
1098    };
1099
1100    final String JavaDoc[] argNames = {
1101        DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME, "current"
1102    };
1103
1104    final InstructionList il = new InstructionList();
1105
1106    final MethodGenerator buildKeys =
1107        new MethodGenerator(ACC_PUBLIC,
1108                org.apache.bcel.generic.Type.VOID,
1109                argTypes, argNames,
1110                "buildKeys", _className, il,
1111                classGen.getConstantPool());
1112
1113    buildKeys.addException("org.apache.xalan.xsltc.TransletException");
1114    
1115    final Enumeration JavaDoc elements = elements();
1116    // Compile code for other top-level elements
1117
while (elements.hasMoreElements()) {
1118        // xsl:key
1119
final Object JavaDoc element = elements.nextElement();
1120        if (element instanceof Key) {
1121        final Key key = (Key)element;
1122        key.translate(classGen, buildKeys);
1123        _keys.put(key.getName(),key);
1124        }
1125    }
1126    
1127    il.append(RETURN);
1128    
1129    // Compute max locals + stack and add method to class
1130
buildKeys.stripAttributes(true);
1131    buildKeys.setMaxLocals();
1132    buildKeys.setMaxStack();
1133    buildKeys.removeNOPs();
1134
1135    classGen.addMethod(buildKeys.getMethod());
1136    
1137    return("("+DOM_INTF_SIG+NODE_ITERATOR_SIG+TRANSLET_OUTPUT_SIG+"I)V");
1138    }
1139
1140    /**
1141     * Compile transform() into the output class. This method is used to
1142     * initialize global variables and global parameters. The current node
1143     * is set to be the document's root node.
1144     */

1145    private void compileTransform(ClassGenerator classGen) {
1146    final ConstantPoolGen cpg = classGen.getConstantPool();
1147
1148    /*
1149     * Define the the method transform with the following signature:
1150     * void transform(DOM, NodeIterator, HandlerBase)
1151     */

1152    final org.apache.bcel.generic.Type[] argTypes =
1153        new org.apache.bcel.generic.Type[3];
1154    argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
1155    argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
1156    argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
1157
1158    final String JavaDoc[] argNames = new String JavaDoc[3];
1159    argNames[0] = DOCUMENT_PNAME;
1160    argNames[1] = ITERATOR_PNAME;
1161    argNames[2] = TRANSLET_OUTPUT_PNAME;
1162
1163    final InstructionList il = new InstructionList();
1164    final MethodGenerator transf =
1165        new MethodGenerator(ACC_PUBLIC,
1166                org.apache.bcel.generic.Type.VOID,
1167                argTypes, argNames,
1168                "transform",
1169                _className,
1170                il,
1171                classGen.getConstantPool());
1172    transf.addException("org.apache.xalan.xsltc.TransletException");
1173
1174    // Define and initialize current with the root node
1175
final LocalVariableGen current =
1176        transf.addLocalVariable("current",
1177                    org.apache.bcel.generic.Type.INT,
1178                    il.getEnd(), null);
1179    final String JavaDoc applyTemplatesSig = classGen.getApplyTemplatesSig();
1180    final int applyTemplates = cpg.addMethodref(getClassName(),
1181                            "applyTemplates",
1182                            applyTemplatesSig);
1183    final int domField = cpg.addFieldref(getClassName(),
1184                         DOM_FIELD,
1185                         DOM_INTF_SIG);
1186
1187    // push translet for PUTFIELD
1188
il.append(classGen.loadTranslet());
1189    // prepare appropriate DOM implementation
1190

1191    if (isMultiDocument()) {
1192        il.append(new NEW(cpg.addClass(MULTI_DOM_CLASS)));
1193        il.append(DUP);
1194    }
1195    
1196    il.append(classGen.loadTranslet());
1197    il.append(transf.loadDOM());
1198    il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS,
1199                             "makeDOMAdapter",
1200                             "("+DOM_INTF_SIG+")"+
1201                             DOM_ADAPTER_SIG)));
1202    // DOMAdapter is on the stack
1203

1204    if (isMultiDocument()) {
1205        final int init = cpg.addMethodref(MULTI_DOM_CLASS,
1206                          "<init>",
1207                          "("+DOM_INTF_SIG+")V");
1208        il.append(new INVOKESPECIAL(init));
1209        // MultiDOM is on the stack
1210
}
1211    
1212    //store to _dom variable
1213
il.append(new PUTFIELD(domField));
1214
1215    // continue with globals initialization
1216
il.append(new PUSH(cpg, DTM.ROOT_NODE));
1217    il.append(new ISTORE(current.getIndex()));
1218
1219    // Transfer the output settings to the output post-processor
1220
il.append(classGen.loadTranslet());
1221    il.append(transf.loadHandler());
1222    final int index = cpg.addMethodref(TRANSLET_CLASS,
1223                       "transferOutputSettings",
1224                       "("+OUTPUT_HANDLER_SIG+")V");
1225    il.append(new INVOKEVIRTUAL(index));
1226
1227        // Compile buildKeys -- TODO: omit if not needed
1228

1229        final String JavaDoc keySig = compileBuildKeys(classGen);
1230        final int keyIdx = cpg.addMethodref(getClassName(),
1231                                               "buildKeys", keySig);
1232        il.append(classGen.loadTranslet()); // The 'this' pointer
1233
il.append(classGen.loadTranslet());
1234        il.append(new GETFIELD(domField)); // The DOM reference
1235
il.append(transf.loadIterator()); // Not really used, but...
1236
il.append(transf.loadHandler()); // The output handler
1237
il.append(new PUSH(cpg, DTM.ROOT_NODE)); // Start with the root node
1238
il.append(new INVOKEVIRTUAL(keyIdx));
1239
1240
1241    // Look for top-level elements that need handling
1242
final Enumeration JavaDoc toplevel = elements();
1243    if ((_globals.size() > 0) || (toplevel.hasMoreElements())) {
1244        // Compile method for handling top-level elements
1245
final String JavaDoc topLevelSig = compileTopLevel(classGen, toplevel);
1246        // Get a reference to that method
1247
final int topLevelIdx = cpg.addMethodref(getClassName(),
1248                             "topLevel",
1249                             topLevelSig);
1250        // Push all parameters on the stack and call topLevel()
1251
il.append(classGen.loadTranslet()); // The 'this' pointer
1252
il.append(classGen.loadTranslet());
1253        il.append(new GETFIELD(domField)); // The DOM reference
1254
il.append(transf.loadIterator());
1255        il.append(transf.loadHandler()); // The output handler
1256
il.append(new INVOKEVIRTUAL(topLevelIdx));
1257    }
1258    
1259
1260
1261
1262    // start document
1263
il.append(transf.loadHandler());
1264    il.append(transf.startDocument());
1265
1266    // push first arg for applyTemplates
1267
il.append(classGen.loadTranslet());
1268    // push translet for GETFIELD to get DOM arg
1269
il.append(classGen.loadTranslet());
1270    il.append(new GETFIELD(domField));
1271    // push remaining 2 args
1272
il.append(transf.loadIterator());
1273    il.append(transf.loadHandler());
1274    il.append(new INVOKEVIRTUAL(applyTemplates));
1275    // endDocument
1276
il.append(transf.loadHandler());
1277    il.append(transf.endDocument());
1278
1279    il.append(RETURN);
1280
1281    // Compute max locals + stack and add method to class
1282
transf.stripAttributes(true);
1283    transf.setMaxLocals();
1284    transf.setMaxStack();
1285    transf.removeNOPs();
1286
1287    classGen.addMethod(transf.getMethod());
1288    }
1289
1290    /**
1291     * Peephole optimization: Remove sequences of [ALOAD, POP].
1292     */

1293    private void peepHoleOptimization(MethodGenerator methodGen) {
1294    final String JavaDoc pattern = "`ALOAD'`POP'`Instruction'";
1295    final InstructionList il = methodGen.getInstructionList();
1296    final InstructionFinder find = new InstructionFinder(il);
1297    for(Iterator JavaDoc iter=find.search(pattern); iter.hasNext(); ) {
1298        InstructionHandle[] match = (InstructionHandle[])iter.next();
1299        try {
1300        il.delete(match[0], match[1]);
1301        }
1302        catch (TargetLostException e) {
1303                // TODO: move target down into the list
1304
}
1305    }
1306    }
1307
1308    public int addParam(Param param) {
1309    _globals.addElement(param);
1310    return _globals.size() - 1;
1311    }
1312
1313    public int addVariable(Variable global) {
1314    _globals.addElement(global);
1315    return _globals.size() - 1;
1316    }
1317
1318    public void display(int indent) {
1319    indent(indent);
1320    Util.println("Stylesheet");
1321    displayContents(indent + IndentIncrement);
1322    }
1323
1324    // do we need this wrapper ?????
1325
public String JavaDoc getNamespace(String JavaDoc prefix) {
1326    return lookupNamespace(prefix);
1327    }
1328
1329    public String JavaDoc getClassName() {
1330    return _className;
1331    }
1332
1333    public Vector JavaDoc getTemplates() {
1334    return _templates;
1335    }
1336
1337    public Vector JavaDoc getAllValidTemplates() {
1338        // Return templates if no imported/included stylesheets
1339
if (_includedStylesheets == null) {
1340            return _templates;
1341        }
1342        
1343        // Is returned value cached?
1344
if (_allValidTemplates == null) {
1345           Vector JavaDoc templates = new Vector JavaDoc();
1346            int size = _includedStylesheets.size();
1347            for (int i = 0; i < size; i++) {
1348                Stylesheet included =(Stylesheet)_includedStylesheets.elementAt(i);
1349                templates.addAll(included.getAllValidTemplates());
1350            }
1351            templates.addAll(_templates);
1352
1353            // Cache results in top-level stylesheet only
1354
if (_parentStylesheet != null) {
1355                return templates;
1356            }
1357            _allValidTemplates = templates;
1358         }
1359        
1360        return _allValidTemplates;
1361    }
1362    
1363    protected void addTemplate(Template template) {
1364        _templates.addElement(template);
1365    }
1366}
1367
Popular Tags