KickJava   Java API By Example, From Geeks To Geeks.

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


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: Parser.java,v 1.64 2004/02/23 10:29:35 aruny Exp $
18  */

19
20 package org.apache.xalan.xsltc.compiler;
21
22 import java.io.File JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.StringReader JavaDoc;
25 import java.util.Dictionary JavaDoc;
26 import java.util.Enumeration JavaDoc;
27 import java.util.Hashtable JavaDoc;
28 import java.util.Properties JavaDoc;
29 import java.util.Stack JavaDoc;
30 import java.util.StringTokenizer JavaDoc;
31 import java.util.Vector JavaDoc;
32
33 import java_cup.runtime.Symbol;
34 import javax.xml.parsers.ParserConfigurationException JavaDoc;
35 import javax.xml.parsers.SAXParser JavaDoc;
36 import javax.xml.parsers.SAXParserFactory JavaDoc;
37
38 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
39 import org.apache.xalan.xsltc.compiler.util.MethodType;
40 import org.apache.xalan.xsltc.compiler.util.Type;
41 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
42 import org.apache.xalan.xsltc.runtime.AttributeList;
43 import org.xml.sax.Attributes JavaDoc;
44 import org.xml.sax.ContentHandler JavaDoc;
45 import org.xml.sax.InputSource JavaDoc;
46 import org.xml.sax.Locator JavaDoc;
47 import org.xml.sax.SAXException JavaDoc;
48 import org.xml.sax.SAXParseException JavaDoc;
49 import org.xml.sax.XMLReader JavaDoc;
50
51 /**
52  * @author Jacek Ambroziak
53  * @author Santiago Pericas-Geertsen
54  * @author G. Todd Miller
55  * @author Morten Jorgensen
56  * @author Erwin Bolwidt <ejb@klomp.org>
57  */

58 public class Parser implements Constants, ContentHandler JavaDoc {
59
60     private static final String JavaDoc XSL = "xsl"; // standard prefix
61
private static final String JavaDoc TRANSLET = "translet"; // extension prefix
62

63     private Locator JavaDoc _locator = null;
64
65     private XSLTC _xsltc; // Reference to the compiler object.
66
private XPathParser _xpathParser; // Reference to the XPath parser.
67
private Vector JavaDoc _errors; // Contains all compilation errors
68
private Vector JavaDoc _warnings; // Contains all compilation errors
69

70     private Hashtable JavaDoc _instructionClasses; // Maps instructions to classes
71
private Hashtable JavaDoc _instructionAttrs;; // reqd and opt attrs
72
private Hashtable JavaDoc _qNames;
73     private Hashtable JavaDoc _namespaces;
74     private QName _useAttributeSets;
75     private QName _excludeResultPrefixes;
76     private QName _extensionElementPrefixes;
77     private Hashtable JavaDoc _variableScope;
78     private Stylesheet _currentStylesheet;
79     private SymbolTable _symbolTable; // Maps QNames to syntax-tree nodes
80
private Output _output;
81     private Template _template; // Reference to the template being parsed.
82

83     private boolean _rootNamespaceDef; // Used for validity check
84

85     private SyntaxTreeNode _root;
86
87     private String JavaDoc _target;
88
89     private int _currentImportPrecedence;
90
91     public Parser(XSLTC xsltc) {
92     _xsltc = xsltc;
93     }
94
95     public void init() {
96     _qNames = new Hashtable JavaDoc(512);
97     _namespaces = new Hashtable JavaDoc();
98     _instructionClasses = new Hashtable JavaDoc();
99     _instructionAttrs = new Hashtable JavaDoc();
100     _variableScope = new Hashtable JavaDoc();
101     _template = null;
102     _errors = new Vector JavaDoc();
103     _warnings = new Vector JavaDoc();
104     _symbolTable = new SymbolTable();
105     _xpathParser = new XPathParser(this);
106     _currentStylesheet = null;
107         _output = null;
108         _root = null;
109         _rootNamespaceDef = false;
110     _currentImportPrecedence = 1;
111     
112     initStdClasses();
113     initInstructionAttrs();
114     initExtClasses();
115     initSymbolTable();
116     
117     _useAttributeSets =
118         getQName(XSLT_URI, XSL, "use-attribute-sets");
119     _excludeResultPrefixes =
120         getQName(XSLT_URI, XSL, "exclude-result-prefixes");
121     _extensionElementPrefixes =
122         getQName(XSLT_URI, XSL, "extension-element-prefixes");
123     }
124
125     public void setOutput(Output output) {
126     if (_output != null) {
127         if (_output.getImportPrecedence() <= output.getImportPrecedence()) {
128         String JavaDoc cdata = _output.getCdata();
129         output.mergeCdata(cdata);
130         _output.disable();
131         _output = output;
132         }
133         else {
134         output.disable();
135         }
136     }
137     else {
138         _output = output;
139     }
140     }
141
142     public Output getOutput() {
143     return _output;
144     }
145
146     public Properties JavaDoc getOutputProperties() {
147     return getTopLevelStylesheet().getOutputProperties();
148     }
149
150     public void addVariable(Variable var) {
151     addVariableOrParam(var);
152     }
153
154     public void addParameter(Param param) {
155     addVariableOrParam(param);
156     }
157
158     private void addVariableOrParam(VariableBase var) {
159     Object JavaDoc existing = _variableScope.get(var.getName());
160     if (existing != null) {
161         if (existing instanceof Stack JavaDoc) {
162         Stack JavaDoc stack = (Stack JavaDoc)existing;
163         stack.push(var);
164         }
165         else if (existing instanceof VariableBase) {
166         Stack JavaDoc stack = new Stack JavaDoc();
167         stack.push(existing);
168         stack.push(var);
169         _variableScope.put(var.getName(), stack);
170         }
171     }
172     else {
173         _variableScope.put(var.getName(), var);
174     }
175     }
176
177     public void removeVariable(QName name) {
178     Object JavaDoc existing = _variableScope.get(name);
179     if (existing instanceof Stack JavaDoc) {
180         Stack JavaDoc stack = (Stack JavaDoc)existing;
181         if (!stack.isEmpty()) stack.pop();
182         if (!stack.isEmpty()) return;
183     }
184     _variableScope.remove(name);
185     }
186
187     public VariableBase lookupVariable(QName name) {
188     Object JavaDoc existing = _variableScope.get(name);
189     if (existing instanceof VariableBase) {
190         return((VariableBase)existing);
191     }
192     else if (existing instanceof Stack JavaDoc) {
193         Stack JavaDoc stack = (Stack JavaDoc)existing;
194         return((VariableBase)stack.peek());
195     }
196     return(null);
197     }
198
199     public void setXSLTC(XSLTC xsltc) {
200     _xsltc = xsltc;
201     }
202
203     public XSLTC getXSLTC() {
204     return _xsltc;
205     }
206
207     public int getCurrentImportPrecedence() {
208     return _currentImportPrecedence;
209     }
210     
211     public int getNextImportPrecedence() {
212     return ++_currentImportPrecedence;
213     }
214
215     public void setCurrentStylesheet(Stylesheet stylesheet) {
216     _currentStylesheet = stylesheet;
217     }
218
219     public Stylesheet getCurrentStylesheet() {
220     return _currentStylesheet;
221     }
222     
223     public Stylesheet getTopLevelStylesheet() {
224     return _xsltc.getStylesheet();
225     }
226
227     public QName getQNameSafe(final String JavaDoc stringRep) {
228     // parse and retrieve namespace
229
final int colon = stringRep.lastIndexOf(':');
230     if (colon != -1) {
231         final String JavaDoc prefix = stringRep.substring(0, colon);
232         final String JavaDoc localname = stringRep.substring(colon + 1);
233         String JavaDoc namespace = null;
234         
235         // Get the namespace uri from the symbol table
236
if (prefix.equals(XMLNS_PREFIX) == false) {
237         namespace = _symbolTable.lookupNamespace(prefix);
238         if (namespace == null) namespace = EMPTYSTRING;
239         }
240         return getQName(namespace, prefix, localname);
241     }
242     else {
243         final String JavaDoc uri = stringRep.equals(XMLNS_PREFIX) ? null
244         : _symbolTable.lookupNamespace(EMPTYSTRING);
245         return getQName(uri, null, stringRep);
246     }
247     }
248     
249     public QName getQName(final String JavaDoc stringRep) {
250     return getQName(stringRep, true, false);
251     }
252
253     public QName getQNameIgnoreDefaultNs(final String JavaDoc stringRep) {
254     return getQName(stringRep, true, true);
255     }
256
257     public QName getQName(final String JavaDoc stringRep, boolean reportError) {
258     return getQName(stringRep, reportError, false);
259     }
260
261     private QName getQName(final String JavaDoc stringRep, boolean reportError,
262     boolean ignoreDefaultNs)
263     {
264     // parse and retrieve namespace
265
final int colon = stringRep.lastIndexOf(':');
266     if (colon != -1) {
267         final String JavaDoc prefix = stringRep.substring(0, colon);
268         final String JavaDoc localname = stringRep.substring(colon + 1);
269         String JavaDoc namespace = null;
270         
271         // Get the namespace uri from the symbol table
272
if (prefix.equals(XMLNS_PREFIX) == false) {
273         namespace = _symbolTable.lookupNamespace(prefix);
274         if (namespace == null && reportError) {
275             final int line = _locator.getLineNumber();
276             ErrorMsg err = new ErrorMsg(ErrorMsg.NAMESPACE_UNDEF_ERR,
277                         line, prefix);
278             reportError(ERROR, err);
279         }
280         }
281         return getQName(namespace, prefix, localname);
282     }
283     else {
284         if (stringRep.equals(XMLNS_PREFIX)) {
285         ignoreDefaultNs = true;
286         }
287         final String JavaDoc defURI = ignoreDefaultNs ? null
288                   : _symbolTable.lookupNamespace(EMPTYSTRING);
289         return getQName(defURI, null, stringRep);
290     }
291     }
292
293     public QName getQName(String JavaDoc namespace, String JavaDoc prefix, String JavaDoc localname) {
294     if (namespace == null || namespace.equals(EMPTYSTRING)) {
295         QName name = (QName)_qNames.get(localname);
296         if (name == null) {
297         name = new QName(null, prefix, localname);
298         _qNames.put(localname, name);
299         }
300         return name;
301     }
302     else {
303         Dictionary JavaDoc space = (Dictionary JavaDoc)_namespaces.get(namespace);
304         if (space == null) {
305         final QName name = new QName(namespace, prefix, localname);
306         _namespaces.put(namespace, space = new Hashtable JavaDoc());
307         space.put(localname, name);
308         return name;
309         }
310         else {
311         QName name = (QName)space.get(localname);
312         if (name == null) {
313             name = new QName(namespace, prefix, localname);
314             space.put(localname, name);
315         }
316         return name;
317         }
318     }
319     }
320     
321     public QName getQName(String JavaDoc scope, String JavaDoc name) {
322     return getQName(scope + name);
323     }
324
325     public QName getQName(QName scope, QName name) {
326     return getQName(scope.toString() + name.toString());
327     }
328
329     public QName getUseAttributeSets() {
330     return _useAttributeSets;
331     }
332
333     public QName getExtensionElementPrefixes() {
334     return _extensionElementPrefixes;
335     }
336
337     public QName getExcludeResultPrefixes() {
338     return _excludeResultPrefixes;
339     }
340     
341     /**
342      * Create an instance of the <code>Stylesheet</code> class,
343      * and then parse, typecheck and compile the instance.
344      * Must be called after <code>parse()</code>.
345      */

346     public Stylesheet makeStylesheet(SyntaxTreeNode element)
347     throws CompilerException {
348     try {
349         Stylesheet stylesheet;
350
351         if (element instanceof Stylesheet) {
352         stylesheet = (Stylesheet)element;
353         }
354         else {
355         stylesheet = new Stylesheet();
356         stylesheet.setSimplified();
357         stylesheet.addElement(element);
358         stylesheet.setAttributes(element.getAttributes());
359
360         // Map the default NS if not already defined
361
if (element.lookupNamespace(EMPTYSTRING) == null) {
362             element.addPrefixMapping(EMPTYSTRING, EMPTYSTRING);
363         }
364         }
365         stylesheet.setParser(this);
366         return stylesheet;
367     }
368     catch (ClassCastException JavaDoc e) {
369         ErrorMsg err = new ErrorMsg(ErrorMsg.NOT_STYLESHEET_ERR, element);
370         throw new CompilerException(err.toString());
371     }
372     }
373     
374     /**
375      * Instanciates a SAX2 parser and generate the AST from the input.
376      */

377     public void createAST(Stylesheet stylesheet) {
378     try {
379         if (stylesheet != null) {
380         stylesheet.parseContents(this);
381         final int precedence = stylesheet.getImportPrecedence();
382         final Enumeration JavaDoc elements = stylesheet.elements();
383         while (elements.hasMoreElements()) {
384             Object JavaDoc child = elements.nextElement();
385             if (child instanceof Text) {
386             final int l = _locator.getLineNumber();
387             ErrorMsg err =
388                 new ErrorMsg(ErrorMsg.ILLEGAL_TEXT_NODE_ERR,l,null);
389             reportError(ERROR, err);
390             }
391         }
392         if (!errorsFound()) {
393             stylesheet.typeCheck(_symbolTable);
394         }
395         }
396     }
397     catch (TypeCheckError e) {
398         reportError(ERROR, new ErrorMsg(e));
399     }
400     }
401
402     /**
403      * Parses a stylesheet and builds the internal abstract syntax tree
404      * @param reader A SAX2 SAXReader (parser)
405      * @param input A SAX2 InputSource can be passed to a SAX reader
406      * @return The root of the abstract syntax tree
407      */

408     public SyntaxTreeNode parse(XMLReader JavaDoc reader, InputSource JavaDoc input) {
409     try {
410         // Parse the input document and build the abstract syntax tree
411
reader.setContentHandler(this);
412         reader.parse(input);
413         // Find the start of the stylesheet within the tree
414
return (SyntaxTreeNode)getStylesheet(_root);
415     }
416     catch (IOException JavaDoc e) {
417         if (_xsltc.debug()) e.printStackTrace();
418         reportError(ERROR,new ErrorMsg(e));
419     }
420     catch (SAXException JavaDoc e) {
421         Throwable JavaDoc ex = e.getException();
422         if (_xsltc.debug()) {
423         e.printStackTrace();
424         if (ex != null) ex.printStackTrace();
425         }
426         reportError(ERROR, new ErrorMsg(e));
427     }
428     catch (CompilerException e) {
429         if (_xsltc.debug()) e.printStackTrace();
430         reportError(ERROR, new ErrorMsg(e));
431     }
432     catch (Exception JavaDoc e) {
433         if (_xsltc.debug()) e.printStackTrace();
434         reportError(ERROR, new ErrorMsg(e));
435     }
436     return null;
437     }
438
439     /**
440      * Parses a stylesheet and builds the internal abstract syntax tree
441      * @param input A SAX2 InputSource can be passed to a SAX reader
442      * @return The root of the abstract syntax tree
443      */

444     public SyntaxTreeNode parse(InputSource JavaDoc input) {
445     try {
446         // Create a SAX parser and get the XMLReader object it uses
447
final SAXParserFactory JavaDoc factory = SAXParserFactory.newInstance();
448         try {
449         factory.setFeature(Constants.NAMESPACE_FEATURE,true);
450         }
451         catch (Exception JavaDoc e) {
452         factory.setNamespaceAware(true);
453         }
454         final SAXParser JavaDoc parser = factory.newSAXParser();
455         final XMLReader JavaDoc reader = parser.getXMLReader();
456         return(parse(reader, input));
457     }
458     catch (ParserConfigurationException JavaDoc e) {
459         ErrorMsg err = new ErrorMsg(ErrorMsg.SAX_PARSER_CONFIG_ERR);
460         reportError(ERROR, err);
461     }
462     catch (SAXParseException JavaDoc e){
463         reportError(ERROR, new ErrorMsg(e.getMessage(),e.getLineNumber()));
464     }
465     catch (SAXException JavaDoc e) {
466         reportError(ERROR, new ErrorMsg(e.getMessage()));
467     }
468     return null;
469     }
470
471     public SyntaxTreeNode getDocumentRoot() {
472     return _root;
473     }
474
475     private String JavaDoc _PImedia = null;
476     private String JavaDoc _PItitle = null;
477     private String JavaDoc _PIcharset = null;
478
479     /**
480      * Set the parameters to use to locate the correct <?xml-stylesheet ...?>
481      * processing instruction in the case where the input document is an
482      * XML document with one or more references to a stylesheet.
483      * @param media The media attribute to be matched. May be null, in which
484      * case the prefered templates will be used (i.e. alternate = no).
485      * @param title The value of the title attribute to match. May be null.
486      * @param charset The value of the charset attribute to match. May be null.
487      */

488     protected void setPIParameters(String JavaDoc media, String JavaDoc title, String JavaDoc charset) {
489     _PImedia = media;
490     _PItitle = title;
491     _PIcharset = charset;
492     }
493
494     /**
495      * Extracts the DOM for the stylesheet. In the case of an embedded
496      * stylesheet, it extracts the DOM subtree corresponding to the
497      * embedded stylesheet that has an 'id' attribute whose value is the
498      * same as the value declared in the <?xml-stylesheet...?> processing
499      * instruction (P.I.). In the xml-stylesheet P.I. the value is labeled
500      * as the 'href' data of the P.I. The extracted DOM representing the
501      * stylesheet is returned as an Element object.
502      */

503     private SyntaxTreeNode getStylesheet(SyntaxTreeNode root)
504     throws CompilerException {
505
506     // Assume that this is a pure XSL stylesheet if there is not
507
// <?xml-stylesheet ....?> processing instruction
508
if (_target == null) {
509         if (!_rootNamespaceDef) {
510         ErrorMsg msg = new ErrorMsg(ErrorMsg.MISSING_XSLT_URI_ERR);
511         throw new CompilerException(msg.toString());
512         }
513         return(root);
514     }
515
516     // Find the xsl:stylesheet or xsl:transform with this reference
517
if (_target.charAt(0) == '#') {
518         SyntaxTreeNode element = findStylesheet(root, _target.substring(1));
519         if (element == null) {
520         ErrorMsg msg = new ErrorMsg(ErrorMsg.MISSING_XSLT_TARGET_ERR,
521                         _target, root);
522         throw new CompilerException(msg.toString());
523         }
524         return(element);
525     }
526     else {
527         return(loadExternalStylesheet(_target));
528     }
529     }
530
531     /**
532      * Find a Stylesheet element with a specific ID attribute value.
533      * This method is used to find a Stylesheet node that is referred
534      * in a <?xml-stylesheet ... ?> processing instruction.
535      */

536     private SyntaxTreeNode findStylesheet(SyntaxTreeNode root, String JavaDoc href) {
537
538     if (root == null) return null;
539
540     if (root instanceof Stylesheet) {
541         String JavaDoc id = root.getAttribute("id");
542         if (id.equals(href)) return root;
543     }
544     Vector JavaDoc children = root.getContents();
545     if (children != null) {
546         final int count = children.size();
547         for (int i = 0; i < count; i++) {
548         SyntaxTreeNode child = (SyntaxTreeNode)children.elementAt(i);
549         SyntaxTreeNode node = findStylesheet(child, href);
550         if (node != null) return node;
551         }
552     }
553     return null;
554     }
555
556     /**
557      * For embedded stylesheets: Load an external file with stylesheet
558      */

559     private SyntaxTreeNode loadExternalStylesheet(String JavaDoc location)
560     throws CompilerException {
561
562     InputSource JavaDoc source;
563
564     // Check if the location is URL or a local file
565
if ((new File JavaDoc(location)).exists())
566         source = new InputSource JavaDoc("file:"+location);
567     else
568         source = new InputSource JavaDoc(location);
569
570     SyntaxTreeNode external = (SyntaxTreeNode)parse(source);
571     return(external);
572     }
573
574     private void initAttrTable(String JavaDoc elementName, String JavaDoc[] attrs) {
575     _instructionAttrs.put(getQName(XSLT_URI, XSL, elementName),
576                 attrs);
577     }
578
579     private void initInstructionAttrs() {
580     initAttrTable("template",
581         new String JavaDoc[] {"match", "name", "priority", "mode"});
582     initAttrTable("stylesheet",
583         new String JavaDoc[] {"id", "version", "extension-element-prefixes",
584         "exclude-result-prefixes"});
585     initAttrTable("transform",
586         new String JavaDoc[] {"id", "version", "extension-element-prefixes",
587         "exclude-result-prefixes"});
588     initAttrTable("text", new String JavaDoc[] {"disable-output-escaping"});
589     initAttrTable("if", new String JavaDoc[] {"test"});
590     initAttrTable("choose", new String JavaDoc[] {});
591     initAttrTable("when", new String JavaDoc[] {"test"});
592     initAttrTable("otherwise", new String JavaDoc[] {});
593     initAttrTable("for-each", new String JavaDoc[] {"select"});
594     initAttrTable("message", new String JavaDoc[] {"terminate"});
595     initAttrTable("number",
596         new String JavaDoc[] {"level", "count", "from", "value", "format", "lang",
597         "letter-value", "grouping-separator", "grouping-size"});
598         initAttrTable("comment", new String JavaDoc[] {});
599     initAttrTable("copy", new String JavaDoc[] {"use-attribute-sets"});
600     initAttrTable("copy-of", new String JavaDoc[] {"select"});
601     initAttrTable("param", new String JavaDoc[] {"name", "select"});
602     initAttrTable("with-param", new String JavaDoc[] {"name", "select"});
603     initAttrTable("variable", new String JavaDoc[] {"name", "select"});
604     initAttrTable("output",
605         new String JavaDoc[] {"method", "version", "encoding",
606         "omit-xml-declaration", "standalone", "doctype-public",
607         "doctype-system", "cdata-section-elements", "indent",
608         "media-type"});
609     initAttrTable("sort",
610        new String JavaDoc[] {"select", "order", "case-order", "lang", "data-type"});
611     initAttrTable("key", new String JavaDoc[] {"name", "match", "use"});
612     initAttrTable("fallback", new String JavaDoc[] {});
613     initAttrTable("attribute", new String JavaDoc[] {"name", "namespace"});
614     initAttrTable("attribute-set",
615         new String JavaDoc[] {"name", "use-attribute-sets"});
616     initAttrTable("value-of",
617         new String JavaDoc[] {"select", "disable-output-escaping"});
618     initAttrTable("element",
619         new String JavaDoc[] {"name", "namespace", "use-attribute-sets"});
620     initAttrTable("call-template", new String JavaDoc[] {"name"});
621     initAttrTable("apply-templates", new String JavaDoc[] {"select", "mode"});
622     initAttrTable("apply-imports", new String JavaDoc[] {});
623     initAttrTable("decimal-format",
624         new String JavaDoc[] {"name", "decimal-separator", "grouping-separator",
625         "infinity", "minus-sign", "NaN", "percent", "per-mille",
626         "zero-digit", "digit", "pattern-separator"});
627     initAttrTable("import", new String JavaDoc[] {"href"});
628     initAttrTable("include", new String JavaDoc[] {"href"});
629     initAttrTable("strip-space", new String JavaDoc[] {"elements"});
630     initAttrTable("preserve-space", new String JavaDoc[] {"elements"});
631     initAttrTable("processing-instruction", new String JavaDoc[] {"name"});
632     initAttrTable("namespace-alias",
633        new String JavaDoc[] {"stylesheet-prefix", "result-prefix"});
634     }
635
636
637
638     /**
639      * Initialize the _instructionClasses Hashtable, which maps XSL element
640      * names to Java classes in this package.
641      */

642     private void initStdClasses() {
643     initStdClass("template", "Template");
644     initStdClass("stylesheet", "Stylesheet");
645     initStdClass("transform", "Stylesheet");
646     initStdClass("text", "Text");
647     initStdClass("if", "If");
648     initStdClass("choose", "Choose");
649     initStdClass("when", "When");
650     initStdClass("otherwise", "Otherwise");
651     initStdClass("for-each", "ForEach");
652     initStdClass("message", "Message");
653     initStdClass("number", "Number");
654     initStdClass("comment", "Comment");
655     initStdClass("copy", "Copy");
656     initStdClass("copy-of", "CopyOf");
657     initStdClass("param", "Param");
658     initStdClass("with-param", "WithParam");
659     initStdClass("variable", "Variable");
660     initStdClass("output", "Output");
661     initStdClass("sort", "Sort");
662     initStdClass("key", "Key");
663     initStdClass("fallback", "Fallback");
664     initStdClass("attribute", "XslAttribute");
665     initStdClass("attribute-set", "AttributeSet");
666     initStdClass("value-of", "ValueOf");
667     initStdClass("element", "XslElement");
668     initStdClass("call-template", "CallTemplate");
669     initStdClass("apply-templates", "ApplyTemplates");
670     initStdClass("apply-imports", "ApplyImports");
671     initStdClass("decimal-format", "DecimalFormatting");
672     initStdClass("import", "Import");
673     initStdClass("include", "Include");
674     initStdClass("strip-space", "Whitespace");
675     initStdClass("preserve-space", "Whitespace");
676     initStdClass("processing-instruction", "ProcessingInstruction");
677     initStdClass("namespace-alias", "NamespaceAlias");
678     }
679     
680     private void initStdClass(String JavaDoc elementName, String JavaDoc className) {
681     _instructionClasses.put(getQName(XSLT_URI, XSL, elementName),
682                 COMPILER_PACKAGE + '.' + className);
683     }
684
685     public boolean elementSupported(String JavaDoc namespace, String JavaDoc localName) {
686     return(_instructionClasses.get(getQName(namespace, XSL, localName)) != null);
687     }
688
689     public boolean functionSupported(String JavaDoc fname) {
690     return(_symbolTable.lookupPrimop(fname) != null);
691     }
692
693     private void initExtClasses() {
694     initExtClass("output", "TransletOutput");
695         initExtClass(REDIRECT_URI, "write", "TransletOutput");
696     }
697
698     private void initExtClass(String JavaDoc elementName, String JavaDoc className) {
699     _instructionClasses.put(getQName(TRANSLET_URI, TRANSLET, elementName),
700                 COMPILER_PACKAGE + '.' + className);
701     }
702
703     private void initExtClass(String JavaDoc namespace, String JavaDoc elementName, String JavaDoc className) {
704         _instructionClasses.put(getQName(namespace, TRANSLET, elementName),
705                                 COMPILER_PACKAGE + '.' + className);
706     }
707
708     /**
709      * Add primops and base functions to the symbol table.
710      */

711     private void initSymbolTable() {
712     MethodType I_V = new MethodType(Type.Int, Type.Void);
713     MethodType I_R = new MethodType(Type.Int, Type.Real);
714     MethodType I_S = new MethodType(Type.Int, Type.String);
715     MethodType I_D = new MethodType(Type.Int, Type.NodeSet);
716     MethodType R_I = new MethodType(Type.Real, Type.Int);
717     MethodType R_V = new MethodType(Type.Real, Type.Void);
718     MethodType R_R = new MethodType(Type.Real, Type.Real);
719     MethodType R_D = new MethodType(Type.Real, Type.NodeSet);
720     MethodType R_O = new MethodType(Type.Real, Type.Reference);
721     MethodType I_I = new MethodType(Type.Int, Type.Int);
722     MethodType D_O = new MethodType(Type.NodeSet, Type.Reference);
723     MethodType D_V = new MethodType(Type.NodeSet, Type.Void);
724     MethodType D_S = new MethodType(Type.NodeSet, Type.String);
725     MethodType D_D = new MethodType(Type.NodeSet, Type.NodeSet);
726     MethodType A_V = new MethodType(Type.Node, Type.Void);
727     MethodType S_V = new MethodType(Type.String, Type.Void);
728     MethodType S_S = new MethodType(Type.String, Type.String);
729     MethodType S_A = new MethodType(Type.String, Type.Node);
730     MethodType S_D = new MethodType(Type.String, Type.NodeSet);
731     MethodType S_O = new MethodType(Type.String, Type.Reference);
732     MethodType B_O = new MethodType(Type.Boolean, Type.Reference);
733     MethodType B_V = new MethodType(Type.Boolean, Type.Void);
734     MethodType B_B = new MethodType(Type.Boolean, Type.Boolean);
735     MethodType B_S = new MethodType(Type.Boolean, Type.String);
736     MethodType D_X = new MethodType(Type.NodeSet, Type.Object);
737     MethodType R_RR = new MethodType(Type.Real, Type.Real, Type.Real);
738     MethodType I_II = new MethodType(Type.Int, Type.Int, Type.Int);
739     MethodType B_RR = new MethodType(Type.Boolean, Type.Real, Type.Real);
740     MethodType B_II = new MethodType(Type.Boolean, Type.Int, Type.Int);
741     MethodType S_SS = new MethodType(Type.String, Type.String, Type.String);
742     MethodType S_DS = new MethodType(Type.String, Type.Real, Type.String);
743     MethodType S_SR = new MethodType(Type.String, Type.String, Type.Real);
744     MethodType O_SO = new MethodType(Type.Reference, Type.String, Type.Reference);
745
746     MethodType D_SS =
747         new MethodType(Type.NodeSet, Type.String, Type.String);
748     MethodType D_SD =
749         new MethodType(Type.NodeSet, Type.String, Type.NodeSet);
750     MethodType B_BB =
751         new MethodType(Type.Boolean, Type.Boolean, Type.Boolean);
752     MethodType B_SS =
753         new MethodType(Type.Boolean, Type.String, Type.String);
754     MethodType S_SD =
755         new MethodType(Type.String, Type.String, Type.NodeSet);
756     MethodType S_DSS =
757         new MethodType(Type.String, Type.Real, Type.String, Type.String);
758     MethodType S_SRR =
759         new MethodType(Type.String, Type.String, Type.Real, Type.Real);
760     MethodType S_SSS =
761         new MethodType(Type.String, Type.String, Type.String, Type.String);
762
763     /*
764      * Standard functions: implemented but not in this table concat().
765      * When adding a new function make sure to uncomment
766      * the corresponding line in <tt>FunctionAvailableCall</tt>.
767      */

768
769     // The following functions are inlined
770

771     _symbolTable.addPrimop("current", A_V);
772     _symbolTable.addPrimop("last", I_V);
773     _symbolTable.addPrimop("position", I_V);
774     _symbolTable.addPrimop("true", B_V);
775     _symbolTable.addPrimop("false", B_V);
776     _symbolTable.addPrimop("not", B_B);
777     _symbolTable.addPrimop("name", S_V);
778     _symbolTable.addPrimop("name", S_A);
779     _symbolTable.addPrimop("generate-id", S_V);
780     _symbolTable.addPrimop("generate-id", S_A);
781     _symbolTable.addPrimop("ceiling", R_R);
782     _symbolTable.addPrimop("floor", R_R);
783     _symbolTable.addPrimop("round", R_R);
784     _symbolTable.addPrimop("contains", B_SS);
785     _symbolTable.addPrimop("number", R_O);
786     _symbolTable.addPrimop("number", R_V);
787     _symbolTable.addPrimop("boolean", B_O);
788     _symbolTable.addPrimop("string", S_O);
789     _symbolTable.addPrimop("string", S_V);
790     _symbolTable.addPrimop("translate", S_SSS);
791     _symbolTable.addPrimop("string-length", I_V);
792     _symbolTable.addPrimop("string-length", I_S);
793     _symbolTable.addPrimop("starts-with", B_SS);
794     _symbolTable.addPrimop("format-number", S_DS);
795     _symbolTable.addPrimop("format-number", S_DSS);
796     _symbolTable.addPrimop("unparsed-entity-uri", S_S);
797     _symbolTable.addPrimop("key", D_SS);
798     _symbolTable.addPrimop("key", D_SD);
799     _symbolTable.addPrimop("id", D_S);
800     _symbolTable.addPrimop("id", D_D);
801     _symbolTable.addPrimop("namespace-uri", S_V);
802     _symbolTable.addPrimop("function-available", B_S);
803     _symbolTable.addPrimop("element-available", B_S);
804     _symbolTable.addPrimop("document", D_S);
805     _symbolTable.addPrimop("document", D_V);
806
807     // The following functions are implemented in the basis library
808
_symbolTable.addPrimop("count", I_D);
809     _symbolTable.addPrimop("sum", R_D);
810     _symbolTable.addPrimop("local-name", S_V);
811     _symbolTable.addPrimop("local-name", S_D);
812     _symbolTable.addPrimop("namespace-uri", S_V);
813     _symbolTable.addPrimop("namespace-uri", S_D);
814     _symbolTable.addPrimop("substring", S_SR);
815     _symbolTable.addPrimop("substring", S_SRR);
816     _symbolTable.addPrimop("substring-after", S_SS);
817     _symbolTable.addPrimop("substring-before", S_SS);
818     _symbolTable.addPrimop("normalize-space", S_V);
819     _symbolTable.addPrimop("normalize-space", S_S);
820     _symbolTable.addPrimop("system-property", S_S);
821
822     // Extensions
823
_symbolTable.addPrimop("nodeset", D_O);
824         _symbolTable.addPrimop("objectType", S_O);
825         _symbolTable.addPrimop("cast", O_SO);
826
827     // Operators +, -, *, /, % defined on real types.
828
_symbolTable.addPrimop("+", R_RR);
829     _symbolTable.addPrimop("-", R_RR);
830     _symbolTable.addPrimop("*", R_RR);
831     _symbolTable.addPrimop("/", R_RR);
832     _symbolTable.addPrimop("%", R_RR);
833
834     // Operators +, -, * defined on integer types.
835
// Operators / and % are not defined on integers (may cause exception)
836
_symbolTable.addPrimop("+", I_II);
837     _symbolTable.addPrimop("-", I_II);
838     _symbolTable.addPrimop("*", I_II);
839
840      // Operators <, <= >, >= defined on real types.
841
_symbolTable.addPrimop("<", B_RR);
842     _symbolTable.addPrimop("<=", B_RR);
843     _symbolTable.addPrimop(">", B_RR);
844     _symbolTable.addPrimop(">=", B_RR);
845
846     // Operators <, <= >, >= defined on int types.
847
_symbolTable.addPrimop("<", B_II);
848     _symbolTable.addPrimop("<=", B_II);
849     _symbolTable.addPrimop(">", B_II);
850     _symbolTable.addPrimop(">=", B_II);
851
852     // Operators <, <= >, >= defined on boolean types.
853
_symbolTable.addPrimop("<", B_BB);
854     _symbolTable.addPrimop("<=", B_BB);
855     _symbolTable.addPrimop(">", B_BB);
856     _symbolTable.addPrimop(">=", B_BB);
857
858     // Operators 'and' and 'or'.
859
_symbolTable.addPrimop("or", B_BB);
860     _symbolTable.addPrimop("and", B_BB);
861
862     // Unary minus.
863
_symbolTable.addPrimop("u-", R_R);
864     _symbolTable.addPrimop("u-", I_I);
865     }
866
867     public SymbolTable getSymbolTable() {
868     return _symbolTable;
869     }
870
871     public Template getTemplate() {
872     return _template;
873     }
874
875     public void setTemplate(Template template) {
876     _template = template;
877     }
878
879     private int _templateIndex = 0;
880
881     public int getTemplateIndex() {
882     return(_templateIndex++);
883     }
884
885     /**
886      * Creates a new node in the abstract syntax tree. This node can be
887      * o) a supported XSLT 1.0 element
888      * o) an unsupported XSLT element (post 1.0)
889      * o) a supported XSLT extension
890      * o) an unsupported XSLT extension
891      * o) a literal result element (not an XSLT element and not an extension)
892      * Unsupported elements do not directly generate an error. We have to wait
893      * until we have received all child elements of an unsupported element to
894      * see if any <xsl:fallback> elements exist.
895      */

896
897     private boolean versionIsOne = true;
898
899     public SyntaxTreeNode makeInstance(String JavaDoc uri, String JavaDoc prefix,
900     String JavaDoc local, Attributes JavaDoc attributes)
901     {
902     SyntaxTreeNode node = null;
903     QName qname = getQName(uri, prefix, local);
904     String JavaDoc className = (String JavaDoc)_instructionClasses.get(qname);
905
906     if (className != null) {
907         try {
908         final Class JavaDoc clazz = ObjectFactory.findProviderClass(
909                     className, ObjectFactory.findClassLoader(), true);
910         node = (SyntaxTreeNode)clazz.newInstance();
911         node.setQName(qname);
912         node.setParser(this);
913         if (_locator != null) {
914             node.setLineNumber(_locator.getLineNumber());
915         }
916         if (node instanceof Stylesheet) {
917             _xsltc.setStylesheet((Stylesheet)node);
918         }
919         checkForSuperfluousAttributes(node, attributes);
920         }
921         catch (ClassNotFoundException JavaDoc e) {
922         ErrorMsg err = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, node);
923         reportError(ERROR, err);
924         }
925         catch (Exception JavaDoc e) {
926         ErrorMsg err = new ErrorMsg(ErrorMsg.INTERNAL_ERR,
927                         e.getMessage(), node);
928         reportError(FATAL, err);
929         }
930     }
931     else {
932         if (uri != null) {
933         // Check if the element belongs in our namespace
934
if (uri.equals(XSLT_URI)) {
935             node = new UnsupportedElement(uri, prefix, local, false);
936             UnsupportedElement element = (UnsupportedElement)node;
937             ErrorMsg msg = new ErrorMsg(ErrorMsg.UNSUPPORTED_XSL_ERR,
938                         _locator.getLineNumber(),local);
939             element.setErrorMessage(msg);
940             if (versionIsOne) {
941                 reportError(UNSUPPORTED,msg);
942             }
943         }
944         // Check if this is an XSLTC extension element
945
else if (uri.equals(TRANSLET_URI)) {
946             node = new UnsupportedElement(uri, prefix, local, true);
947             UnsupportedElement element = (UnsupportedElement)node;
948             ErrorMsg msg = new ErrorMsg(ErrorMsg.UNSUPPORTED_EXT_ERR,
949                         _locator.getLineNumber(),local);
950             element.setErrorMessage(msg);
951         }
952         // Check if this is an extension of some other XSLT processor
953
else {
954             Stylesheet sheet = _xsltc.getStylesheet();
955             if ((sheet != null) && (sheet.isExtension(uri))) {
956             if (sheet != (SyntaxTreeNode)_parentStack.peek()) {
957                 node = new UnsupportedElement(uri, prefix, local, true);
958                 UnsupportedElement elem = (UnsupportedElement)node;
959                 ErrorMsg msg =
960                 new ErrorMsg(ErrorMsg.UNSUPPORTED_EXT_ERR,
961                          _locator.getLineNumber(),
962                          prefix+":"+local);
963                 elem.setErrorMessage(msg);
964             }
965             }
966         }
967         }
968         if (node == null) node = new LiteralElement();
969     }
970     if ((node != null) && (node instanceof LiteralElement)) {
971         ((LiteralElement)node).setQName(qname);
972     }
973     return(node);
974     }
975
976     /**
977      * checks the list of attributes against a list of allowed attributes
978      * for a particular element node.
979      */

980     private void checkForSuperfluousAttributes(SyntaxTreeNode node,
981     Attributes JavaDoc attrs)
982     {
983     QName qname = node.getQName();
984     boolean isStylesheet = (node instanceof Stylesheet);
985         String JavaDoc[] legal = (String JavaDoc[]) _instructionAttrs.get(qname);
986     if (versionIsOne && legal != null) {
987         int j;
988         final int n = attrs.getLength();
989
990         for (int i = 0; i < n; i++) {
991             final String JavaDoc attrQName = attrs.getQName(i);
992
993             if (isStylesheet && attrQName.equals("version")) {
994                 versionIsOne = attrs.getValue(i).equals("1.0");
995             }
996
997         // Ignore if special or if it has a prefix
998
if (attrQName.startsWith("xml") ||
999             attrQName.indexOf(':') > 0) continue;
1000
1001            for (j = 0; j < legal.length; j++) {
1002                if (attrQName.equalsIgnoreCase(legal[j])) {
1003                break;
1004            }
1005            }
1006            if (j == legal.length) {
1007                final ErrorMsg err =
1008                new ErrorMsg(ErrorMsg.ILLEGAL_ATTRIBUTE_ERR,
1009                attrQName, node);
1010            reportError(WARNING, err);
1011            }
1012        }
1013        }
1014    }
1015
1016
1017    /**
1018     * Parse an XPath expression:
1019     * @parent - XSL element where the expression occured
1020     * @exp - textual representation of the expression
1021     */

1022    public Expression parseExpression(SyntaxTreeNode parent, String JavaDoc exp) {
1023    return (Expression)parseTopLevel(parent, "<EXPRESSION>"+exp, null);
1024    }
1025
1026    /**
1027     * Parse an XPath expression:
1028     * @parent - XSL element where the expression occured
1029     * @attr - name of this element's attribute to get expression from
1030     * @def - default expression (if the attribute was not found)
1031     */

1032    public Expression parseExpression(SyntaxTreeNode parent,
1033                      String JavaDoc attr, String JavaDoc def) {
1034    // Get the textual representation of the expression (if any)
1035
String JavaDoc exp = parent.getAttribute(attr);
1036    // Use the default expression if none was found
1037
if ((exp.length() == 0) && (def != null)) exp = def;
1038    // Invoke the XPath parser
1039
return (Expression)parseTopLevel(parent, "<EXPRESSION>"+exp, exp);
1040    }
1041
1042    /**
1043     * Parse an XPath pattern:
1044     * @parent - XSL element where the pattern occured
1045     * @exp - textual representation of the pattern
1046     */

1047    public Pattern parsePattern(SyntaxTreeNode parent, String JavaDoc pattern) {
1048    return (Pattern)parseTopLevel(parent, "<PATTERN>"+pattern, pattern);
1049    }
1050
1051    /**
1052     * Parse an XPath pattern:
1053     * @parent - XSL element where the pattern occured
1054     * @attr - name of this element's attribute to get pattern from
1055     * @def - default pattern (if the attribute was not found)
1056     */

1057    public Pattern parsePattern(SyntaxTreeNode parent,
1058                String JavaDoc attr, String JavaDoc def) {
1059    // Get the textual representation of the pattern (if any)
1060
String JavaDoc pattern = parent.getAttribute(attr);
1061    // Use the default pattern if none was found
1062
if ((pattern.length() == 0) && (def != null)) pattern = def;
1063    // Invoke the XPath parser
1064
return (Pattern)parseTopLevel(parent, "<PATTERN>"+pattern, pattern);
1065    }
1066
1067    /**
1068     * Parse an XPath expression or pattern using the generated XPathParser
1069     * The method will return a Dummy node if the XPath parser fails.
1070     */

1071    private SyntaxTreeNode parseTopLevel(SyntaxTreeNode parent, String JavaDoc text,
1072                     String JavaDoc expression) {
1073    int line = 0;
1074    if (_locator != null) line = _locator.getLineNumber();
1075
1076    try {
1077        _xpathParser.setScanner(new XPathLexer(new StringReader JavaDoc(text)));
1078        Symbol result = _xpathParser.parse(expression, line);
1079        if (result != null) {
1080        final SyntaxTreeNode node = (SyntaxTreeNode)result.value;
1081        if (node != null) {
1082            node.setParser(this);
1083            node.setParent(parent);
1084            node.setLineNumber(line);
1085// System.out.println("e = " + text + " " + node);
1086
return node;
1087        }
1088        }
1089        reportError(ERROR, new ErrorMsg(ErrorMsg.XPATH_PARSER_ERR,
1090                        expression, parent));
1091    }
1092    catch (Exception JavaDoc e) {
1093        if (_xsltc.debug()) e.printStackTrace();
1094        reportError(ERROR, new ErrorMsg(ErrorMsg.XPATH_PARSER_ERR,
1095                        expression, parent));
1096    }
1097
1098    // Return a dummy pattern (which is an expression)
1099
SyntaxTreeNode.Dummy.setParser(this);
1100        return SyntaxTreeNode.Dummy;
1101    }
1102
1103    /************************ ERROR HANDLING SECTION ************************/
1104
1105    /**
1106     * Returns true if there were any errors during compilation
1107     */

1108    public boolean errorsFound() {
1109    return _errors.size() > 0;
1110    }
1111
1112    /**
1113     * Prints all compile-time errors
1114     */

1115    public void printErrors() {
1116    final int size = _errors.size();
1117    if (size > 0) {
1118        System.err.println(new ErrorMsg(ErrorMsg.COMPILER_ERROR_KEY));
1119        for (int i = 0; i < size; i++) {
1120        System.err.println(" " + _errors.elementAt(i));
1121        }
1122    }
1123    }
1124
1125    /**
1126     * Prints all compile-time warnings
1127     */

1128    public void printWarnings() {
1129    final int size = _warnings.size();
1130    if (size > 0) {
1131        System.err.println(new ErrorMsg(ErrorMsg.COMPILER_WARNING_KEY));
1132        for (int i = 0; i < size; i++) {
1133        System.err.println(" " + _warnings.elementAt(i));
1134        }
1135    }
1136    }
1137
1138    /**
1139     * Common error/warning message handler
1140     */

1141    public void reportError(final int category, final ErrorMsg error) {
1142    switch (category) {
1143    case Constants.INTERNAL:
1144        // Unexpected internal errors, such as null-ptr exceptions, etc.
1145
// Immediately terminates compilation, no translet produced
1146
_errors.addElement(error);
1147        break;
1148    case Constants.UNSUPPORTED:
1149        // XSLT elements that are not implemented and unsupported ext.
1150
// Immediately terminates compilation, no translet produced
1151
_errors.addElement(error);
1152        break;
1153    case Constants.FATAL:
1154        // Fatal error in the stylesheet input (parsing or content)
1155
// Immediately terminates compilation, no translet produced
1156
_errors.addElement(error);
1157        break;
1158    case Constants.ERROR:
1159        // Other error in the stylesheet input (parsing or content)
1160
// Does not terminate compilation, no translet produced
1161
_errors.addElement(error);
1162        break;
1163    case Constants.WARNING:
1164        // Other error in the stylesheet input (content errors only)
1165
// Does not terminate compilation, a translet is produced
1166
_warnings.addElement(error);
1167        break;
1168    }
1169    }
1170
1171    public Vector JavaDoc getErrors() {
1172    return _errors;
1173    }
1174
1175    public Vector JavaDoc getWarnings() {
1176    return _warnings;
1177    }
1178
1179    /************************ SAX2 ContentHandler INTERFACE *****************/
1180
1181    private Stack JavaDoc _parentStack = null;
1182    private Hashtable JavaDoc _prefixMapping = null;
1183
1184    /**
1185     * SAX2: Receive notification of the beginning of a document.
1186     */

1187    public void startDocument() {
1188    _root = null;
1189    _target = null;
1190    _prefixMapping = null;
1191    _parentStack = new Stack JavaDoc();
1192    }
1193
1194    /**
1195     * SAX2: Receive notification of the end of a document.
1196     */

1197    public void endDocument() { }
1198
1199
1200    /**
1201     * SAX2: Begin the scope of a prefix-URI Namespace mapping.
1202     * This has to be passed on to the symbol table!
1203     */

1204    public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri) {
1205    if (_prefixMapping == null) {
1206        _prefixMapping = new Hashtable JavaDoc();
1207    }
1208    _prefixMapping.put(prefix, uri);
1209    }
1210
1211    /**
1212     * SAX2: End the scope of a prefix-URI Namespace mapping.
1213     * This has to be passed on to the symbol table!
1214     */

1215    public void endPrefixMapping(String JavaDoc prefix) { }
1216
1217    /**
1218     * SAX2: Receive notification of the beginning of an element.
1219     * The parser may re-use the attribute list that we're passed so
1220     * we clone the attributes in our own Attributes implementation
1221     */

1222    public void startElement(String JavaDoc uri, String JavaDoc localname,
1223                 String JavaDoc qname, Attributes JavaDoc attributes)
1224    throws SAXException JavaDoc {
1225    final int col = qname.lastIndexOf(':');
1226    final String JavaDoc prefix = (col == -1) ? null : qname.substring(0, col);
1227
1228    SyntaxTreeNode element = makeInstance(uri, prefix,
1229                    localname, attributes);
1230    if (element == null) {
1231        ErrorMsg err = new ErrorMsg(ErrorMsg.ELEMENT_PARSE_ERR,
1232                    prefix+':'+localname);
1233        throw new SAXException JavaDoc(err.toString());
1234    }
1235
1236    // If this is the root element of the XML document we need to make sure
1237
// that it contains a definition of the XSL namespace URI
1238
if (_root == null) {
1239        if ((_prefixMapping == null) ||
1240        (_prefixMapping.containsValue(Constants.XSLT_URI) == false))
1241        _rootNamespaceDef = false;
1242        else
1243        _rootNamespaceDef = true;
1244        _root = element;
1245    }
1246    else {
1247        SyntaxTreeNode parent = (SyntaxTreeNode)_parentStack.peek();
1248        parent.addElement(element);
1249        element.setParent(parent);
1250    }
1251    element.setAttributes((Attributes JavaDoc)new AttributeList(attributes));
1252    element.setPrefixMapping(_prefixMapping);
1253    
1254    if (element instanceof Stylesheet) {
1255        // Extension elements and excluded elements have to be
1256
// handled at this point in order to correctly generate
1257
// Fallback elements from <xsl:fallback>s.
1258
getSymbolTable().setCurrentNode(element);
1259        ((Stylesheet)element).excludeExtensionPrefixes(this);
1260    }
1261
1262    _prefixMapping = null;
1263    _parentStack.push(element);
1264    }
1265
1266    /**
1267     * SAX2: Receive notification of the end of an element.
1268     */

1269    public void endElement(String JavaDoc uri, String JavaDoc localname, String JavaDoc qname) {
1270    _parentStack.pop();
1271    }
1272
1273    /**
1274     * SAX2: Receive notification of character data.
1275     */

1276    public void characters(char[] ch, int start, int length) {
1277    String JavaDoc string = new String JavaDoc(ch, start, length);
1278    SyntaxTreeNode parent = (SyntaxTreeNode)_parentStack.peek();
1279
1280    if (string.length() == 0) return;
1281
1282    // If this text occurs within an <xsl:text> element we append it
1283
// as-is to the existing text element
1284
if (parent instanceof Text) {
1285        ((Text)parent).setText(string);
1286        return;
1287    }
1288
1289    // Ignore text nodes that occur directly under <xsl:stylesheet>
1290
if (parent instanceof Stylesheet) return;
1291
1292    SyntaxTreeNode bro = parent.lastChild();
1293    if ((bro != null) && (bro instanceof Text)) {
1294        Text text = (Text)bro;
1295        if (!text.isTextElement()) {
1296        if ((length > 1) || ( ((int)ch[0]) < 0x100)) {
1297            text.setText(string);
1298            return;
1299        }
1300        }
1301    }
1302
1303    // Add it as a regular text node otherwise
1304
parent.addElement(new Text(string));
1305    }
1306
1307    private String JavaDoc getTokenValue(String JavaDoc token) {
1308    final int start = token.indexOf('"');
1309    final int stop = token.lastIndexOf('"');
1310    return token.substring(start+1, stop);
1311    }
1312
1313    /**
1314     * SAX2: Receive notification of a processing instruction.
1315     * These require special handling for stylesheet PIs.
1316     */

1317    public void processingInstruction(String JavaDoc name, String JavaDoc value) {
1318    // We only handle the <?xml-stylesheet ...?> PI
1319
if ((_target == null) && (name.equals("xml-stylesheet"))) {
1320
1321        String JavaDoc href = null; // URI of stylesheet found
1322
String JavaDoc media = null; // Media of stylesheet found
1323
String JavaDoc title = null; // Title of stylesheet found
1324
String JavaDoc charset = null; // Charset of stylesheet found
1325

1326        // Get the attributes from the processing instruction
1327
StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(value);
1328        while (tokens.hasMoreElements()) {
1329        String JavaDoc token = (String JavaDoc)tokens.nextElement();
1330        if (token.startsWith("href"))
1331            href = getTokenValue(token);
1332        else if (token.startsWith("media"))
1333            media = getTokenValue(token);
1334        else if (token.startsWith("title"))
1335            title = getTokenValue(token);
1336        else if (token.startsWith("charset"))
1337            charset = getTokenValue(token);
1338        }
1339
1340        // Set the target to this PI's href if the parameters are
1341
// null or match the corresponding attributes of this PI.
1342
if ( ((_PImedia == null) || (_PImedia.equals(media))) &&
1343         ((_PItitle == null) || (_PImedia.equals(title))) &&
1344         ((_PIcharset == null) || (_PImedia.equals(charset))) ) {
1345        _target = href;
1346        }
1347    }
1348    }
1349
1350    /**
1351     * IGNORED - all ignorable whitespace is ignored
1352     */

1353    public void ignorableWhitespace(char[] ch, int start, int length) { }
1354
1355    /**
1356     * IGNORED - we do not have to do anything with skipped entities
1357     */

1358    public void skippedEntity(String JavaDoc name) { }
1359
1360    /**
1361     * Store the document locator to later retrieve line numbers of all
1362     * elements from the stylesheet
1363     */

1364    public void setDocumentLocator(Locator JavaDoc locator) {
1365    _locator = locator;
1366    }
1367
1368}
1369
Popular Tags