KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xalan > internal > 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.1.2.1 2006/09/19 01:06:32 jeffsuttor Exp $
18  */

19
20 package com.sun.org.apache.xalan.internal.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 com.sun.java_cup.internal.runtime.Symbol;
34 import javax.xml.XMLConstants JavaDoc;
35 import javax.xml.parsers.ParserConfigurationException JavaDoc;
36 import javax.xml.parsers.SAXParser JavaDoc;
37 import javax.xml.parsers.SAXParserFactory JavaDoc;
38
39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
41 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
42 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
43 import com.sun.org.apache.xalan.internal.xsltc.runtime.AttributeList;
44 import org.xml.sax.Attributes JavaDoc;
45 import org.xml.sax.ContentHandler JavaDoc;
46 import org.xml.sax.InputSource JavaDoc;
47 import org.xml.sax.Locator JavaDoc;
48 import org.xml.sax.SAXException JavaDoc;
49 import org.xml.sax.SAXParseException JavaDoc;
50 import org.xml.sax.XMLReader JavaDoc;
51
52 /**
53  * @author Jacek Ambroziak
54  * @author Santiago Pericas-Geertsen
55  * @author G. Todd Miller
56  * @author Morten Jorgensen
57  * @author Erwin Bolwidt <ejb@klomp.org>
58  */

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

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

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

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

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

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

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

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

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

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

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

545     private SyntaxTreeNode findStylesheet(SyntaxTreeNode root, String JavaDoc href) {
546
547     if (root == null) return null;
548
549     if (root instanceof Stylesheet) {
550         String JavaDoc id = root.getAttribute("id");
551         if (id.equals(href)) return root;
552     }
553     Vector JavaDoc children = root.getContents();
554     if (children != null) {
555         final int count = children.size();
556         for (int i = 0; i < count; i++) {
557         SyntaxTreeNode child = (SyntaxTreeNode)children.elementAt(i);
558         SyntaxTreeNode node = findStylesheet(child, href);
559         if (node != null) return node;
560         }
561     }
562     return null;
563     }
564
565     /**
566      * For embedded stylesheets: Load an external file with stylesheet
567      */

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

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

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

777
778     // The following functions are inlined
779

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

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

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

1034    public Expression parseExpression(SyntaxTreeNode parent, String JavaDoc exp) {
1035    return (Expression)parseTopLevel(parent, "<EXPRESSION>"+exp, null);
1036    }
1037
1038    /**
1039     * Parse an XPath expression:
1040     * @parent - XSL element where the expression occured
1041     * @attr - name of this element's attribute to get expression from
1042     * @def - default expression (if the attribute was not found)
1043     */

1044    public Expression parseExpression(SyntaxTreeNode parent,
1045                      String JavaDoc attr, String JavaDoc def) {
1046    // Get the textual representation of the expression (if any)
1047
String JavaDoc exp = parent.getAttribute(attr);
1048    // Use the default expression if none was found
1049
if ((exp.length() == 0) && (def != null)) exp = def;
1050    // Invoke the XPath parser
1051
return (Expression)parseTopLevel(parent, "<EXPRESSION>"+exp, exp);
1052    }
1053
1054    /**
1055     * Parse an XPath pattern:
1056     * @parent - XSL element where the pattern occured
1057     * @exp - textual representation of the pattern
1058     */

1059    public Pattern parsePattern(SyntaxTreeNode parent, String JavaDoc pattern) {
1060    return (Pattern)parseTopLevel(parent, "<PATTERN>"+pattern, pattern);
1061    }
1062
1063    /**
1064     * Parse an XPath pattern:
1065     * @parent - XSL element where the pattern occured
1066     * @attr - name of this element's attribute to get pattern from
1067     * @def - default pattern (if the attribute was not found)
1068     */

1069    public Pattern parsePattern(SyntaxTreeNode parent,
1070                String JavaDoc attr, String JavaDoc def) {
1071    // Get the textual representation of the pattern (if any)
1072
String JavaDoc pattern = parent.getAttribute(attr);
1073    // Use the default pattern if none was found
1074
if ((pattern.length() == 0) && (def != null)) pattern = def;
1075    // Invoke the XPath parser
1076
return (Pattern)parseTopLevel(parent, "<PATTERN>"+pattern, pattern);
1077    }
1078
1079    /**
1080     * Parse an XPath expression or pattern using the generated XPathParser
1081     * The method will return a Dummy node if the XPath parser fails.
1082     */

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

1120    public boolean errorsFound() {
1121    return _errors.size() > 0;
1122    }
1123
1124    /**
1125     * Prints all compile-time errors
1126     */

1127    public void printErrors() {
1128    final int size = _errors.size();
1129    if (size > 0) {
1130        System.err.println(new ErrorMsg(ErrorMsg.COMPILER_ERROR_KEY));
1131        for (int i = 0; i < size; i++) {
1132        System.err.println(" " + _errors.elementAt(i));
1133        }
1134    }
1135    }
1136
1137    /**
1138     * Prints all compile-time warnings
1139     */

1140    public void printWarnings() {
1141    final int size = _warnings.size();
1142    if (size > 0) {
1143        System.err.println(new ErrorMsg(ErrorMsg.COMPILER_WARNING_KEY));
1144        for (int i = 0; i < size; i++) {
1145        System.err.println(" " + _warnings.elementAt(i));
1146        }
1147    }
1148    }
1149
1150    /**
1151     * Common error/warning message handler
1152     */

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

1199    public void startDocument() {
1200    _root = null;
1201    _target = null;
1202    _prefixMapping = null;
1203    _parentStack = new Stack JavaDoc();
1204    }
1205
1206    /**
1207     * SAX2: Receive notification of the end of a document.
1208     */

1209    public void endDocument() { }
1210
1211
1212    /**
1213     * SAX2: Begin the scope of a prefix-URI Namespace mapping.
1214     * This has to be passed on to the symbol table!
1215     */

1216    public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri) {
1217    if (_prefixMapping == null) {
1218        _prefixMapping = new Hashtable JavaDoc();
1219    }
1220    _prefixMapping.put(prefix, uri);
1221    }
1222
1223    /**
1224     * SAX2: End the scope of a prefix-URI Namespace mapping.
1225     * This has to be passed on to the symbol table!
1226     */

1227    public void endPrefixMapping(String JavaDoc prefix) { }
1228
1229    /**
1230     * SAX2: Receive notification of the beginning of an element.
1231     * The parser may re-use the attribute list that we're passed so
1232     * we clone the attributes in our own Attributes implementation
1233     */

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

1281    public void endElement(String JavaDoc uri, String JavaDoc localname, String JavaDoc qname) {
1282    _parentStack.pop();
1283    }
1284
1285    /**
1286     * SAX2: Receive notification of character data.
1287     */

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

1329    public void processingInstruction(String JavaDoc name, String JavaDoc value) {
1330    // We only handle the <?xml-stylesheet ...?> PI
1331
if ((_target == null) && (name.equals("xml-stylesheet"))) {
1332
1333        String JavaDoc href = null; // URI of stylesheet found
1334
String JavaDoc media = null; // Media of stylesheet found
1335
String JavaDoc title = null; // Title of stylesheet found
1336
String JavaDoc charset = null; // Charset of stylesheet found
1337

1338        // Get the attributes from the processing instruction
1339
StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(value);
1340        while (tokens.hasMoreElements()) {
1341        String JavaDoc token = (String JavaDoc)tokens.nextElement();
1342        if (token.startsWith("href"))
1343            href = getTokenValue(token);
1344        else if (token.startsWith("media"))
1345            media = getTokenValue(token);
1346        else if (token.startsWith("title"))
1347            title = getTokenValue(token);
1348        else if (token.startsWith("charset"))
1349            charset = getTokenValue(token);
1350        }
1351
1352        // Set the target to this PI's href if the parameters are
1353
// null or match the corresponding attributes of this PI.
1354
if ( ((_PImedia == null) || (_PImedia.equals(media))) &&
1355         ((_PItitle == null) || (_PImedia.equals(title))) &&
1356         ((_PIcharset == null) || (_PImedia.equals(charset))) ) {
1357        _target = href;
1358        }
1359    }
1360    }
1361
1362    /**
1363     * IGNORED - all ignorable whitespace is ignored
1364     */

1365    public void ignorableWhitespace(char[] ch, int start, int length) { }
1366
1367    /**
1368     * IGNORED - we do not have to do anything with skipped entities
1369     */

1370    public void skippedEntity(String JavaDoc name) { }
1371
1372    /**
1373     * Store the document locator to later retrieve line numbers of all
1374     * elements from the stylesheet
1375     */

1376    public void setDocumentLocator(Locator JavaDoc locator) {
1377    _locator = locator;
1378    }
1379
1380}
1381
Popular Tags