1 /*
2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one or more
6 * contributor license agreements. See the NOTICE file distributed with
7 * this work for additional information regarding copyright ownership.
8 * The ASF licenses this file to You under the Apache License, Version 2.0
9 * (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20 /*
21 * $Id: Parser.java,v 1.2.4.1 2005/09/13 12:14:32 pvedula Exp $
22 */
23
24 package com.sun.org.apache.xalan.internal.xsltc.compiler;
25
26 import com.sun.java_cup.internal.runtime.Symbol;
27 import com.sun.org.apache.xalan.internal.XalanConstants;
28 import com.sun.org.apache.xalan.internal.utils.FactoryImpl;
29 import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
30 import com.sun.org.apache.xalan.internal.utils.SecuritySupport;
31 import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager;
32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
36 import com.sun.org.apache.xml.internal.serializer.utils.SystemIDResolver;
37 import java.io.File;
38 import java.io.IOException;
39 import java.io.StringReader;
40 import java.util.ArrayList;
41 import java.util.HashMap;
42 import java.util.Iterator;
55 import org.xml.sax.Attributes;
56 import org.xml.sax.ContentHandler;
57 import org.xml.sax.InputSource;
58 import org.xml.sax.Locator;
59 import org.xml.sax.SAXException;
60 import org.xml.sax.SAXNotRecognizedException;
61 import org.xml.sax.SAXNotSupportedException;
62 import org.xml.sax.SAXParseException;
63 import org.xml.sax.XMLReader;
64 import org.xml.sax.helpers.AttributesImpl;
65
66 /**
67 * @author Jacek Ambroziak
68 * @author Santiago Pericas-Geertsen
69 * @author G. Todd Miller
70 * @author Morten Jorgensen
71 * @author Erwin Bolwidt <ejb@klomp.org>
72 */
73 public class Parser implements Constants, ContentHandler {
74
75 private static final String XSL = "xsl"; // standard prefix
76 private static final String TRANSLET = "translet"; // extension prefix
77
78 private Locator _locator = null;
79
80 private XSLTC _xsltc; // Reference to the compiler object.
81 private XPathParser _xpathParser; // Reference to the XPath parser.
82 private ArrayList<ErrorMsg> _errors; // Contains all compilation errors
83 private ArrayList<ErrorMsg> _warnings; // Contains all compilation errors
84
85 private Map<String, String> _instructionClasses; // Maps instructions to classes
86 private Map<String, String[]> _instructionAttrs; // reqd and opt attrs
87 private Map<String, QName> _qNames;
88 private Map<String, Map> _namespaces;
89 private QName _useAttributeSets;
90 private QName _excludeResultPrefixes;
91 private QName _extensionElementPrefixes;
92 private Map<String, Object> _variableScope;
93 private Stylesheet _currentStylesheet;
94 private SymbolTable _symbolTable; // Maps QNames to syntax-tree nodes
95 private Output _output;
96 private Template _template; // Reference to the template being parsed.
97
98 private boolean _rootNamespaceDef; // Used for validity check
99
100 private SyntaxTreeNode _root;
101
102 private String _target;
103
104 private int _currentImportPrecedence;
105
106 private boolean _useServicesMechanism = true;
107
108 public Parser(XSLTC xsltc, boolean useServicesMechanism) {
126 _root = null;
127 _rootNamespaceDef = false;
128 _currentImportPrecedence = 1;
129
130 initStdClasses();
131 initInstructionAttrs();
132 initExtClasses();
133 initSymbolTable();
134
135 _useAttributeSets =
136 getQName(XSLT_URI, XSL, "use-attribute-sets");
137 _excludeResultPrefixes =
138 getQName(XSLT_URI, XSL, "exclude-result-prefixes");
139 _extensionElementPrefixes =
140 getQName(XSLT_URI, XSL, "extension-element-prefixes");
141 }
142
143 public void setOutput(Output output) {
144 if (_output != null) {
145 if (_output.getImportPrecedence() <= output.getImportPrecedence()) {
146 String cdata = _output.getCdata();
147 output.mergeOutput(_output);
148 _output.disable();
149 _output = output;
150 }
151 else {
152 output.disable();
153 }
154 }
155 else {
156 _output = output;
157 }
158 }
159
160 public Output getOutput() {
161 return _output;
162 }
163
164 public Properties getOutputProperties() {
165 return getTopLevelStylesheet().getOutputProperties();
166 }
167
168 public void addVariable(Variable var) {
169 addVariableOrParam(var);
170 }
171
172 public void addParameter(Param param) {
173 addVariableOrParam(param);
174 }
175
176 private void addVariableOrParam(VariableBase var) {
177 Object existing = _variableScope.get(var.getName().getStringRep());
178 if (existing != null) {
179 if (existing instanceof Stack) {
180 Stack stack = (Stack)existing;
181 stack.push(var);
182 }
183 else if (existing instanceof VariableBase) {
184 Stack stack = new Stack();
185 stack.push(existing);
186 stack.push(var);
187 _variableScope.put(var.getName().getStringRep(), stack);
188 }
189 }
190 else {
191 _variableScope.put(var.getName().getStringRep(), var);
192 }
193 }
194
195 public void removeVariable(QName name) {
196 Object existing = _variableScope.get(name.getStringRep());
197 if (existing instanceof Stack) {
198 Stack stack = (Stack)existing;
199 if (!stack.isEmpty()) stack.pop();
200 if (!stack.isEmpty()) return;
201 }
202 _variableScope.remove(name.getStringRep());
203 }
204
205 public VariableBase lookupVariable(QName name) {
206 Object existing = _variableScope.get(name.getStringRep());
207 if (existing instanceof VariableBase) {
208 return((VariableBase)existing);
209 }
210 else if (existing instanceof Stack) {
211 Stack stack = (Stack)existing;
212 return((VariableBase)stack.peek());
213 }
214 return(null);
215 }
216
217 public void setXSLTC(XSLTC xsltc) {
218 _xsltc = xsltc;
219 }
220
221 public XSLTC getXSLTC() {
222 return _xsltc;
223 }
224
225 public int getCurrentImportPrecedence() {
226 return _currentImportPrecedence;
227 }
228
229 public int getNextImportPrecedence() {
230 return ++_currentImportPrecedence;
231 }
232
233 public void setCurrentStylesheet(Stylesheet stylesheet) {
234 _currentStylesheet = stylesheet;
384 if (element.lookupNamespace(EMPTYSTRING) == null) {
385 element.addPrefixMapping(EMPTYSTRING, EMPTYSTRING);
386 }
387 }
388 stylesheet.setParser(this);
389 return stylesheet;
390 }
391 catch (ClassCastException e) {
392 ErrorMsg err = new ErrorMsg(ErrorMsg.NOT_STYLESHEET_ERR, element);
393 throw new CompilerException(err.toString());
394 }
395 }
396
397 /**
398 * Instanciates a SAX2 parser and generate the AST from the input.
399 */
400 public void createAST(Stylesheet stylesheet) {
401 try {
402 if (stylesheet != null) {
403 stylesheet.parseContents(this);
404 final int precedence = stylesheet.getImportPrecedence();
405 final Iterator<SyntaxTreeNode> elements = stylesheet.elements();
406 while (elements.hasNext()) {
407 Object child = elements.next();
408 if (child instanceof Text) {
409 final int l = getLineNumber();
410 ErrorMsg err =
411 new ErrorMsg(ErrorMsg.ILLEGAL_TEXT_NODE_ERR,l,null);
412 reportError(ERROR, err);
413 }
414 }
415 if (!errorsFound()) {
416 stylesheet.typeCheck(_symbolTable);
417 }
418 }
419 }
420 catch (TypeCheckError e) {
421 reportError(ERROR, new ErrorMsg(ErrorMsg.JAXP_COMPILE_ERR, e));
422 }
423 }
424
425 /**
426 * Parses a stylesheet and builds the internal abstract syntax tree
427 * @param reader A SAX2 SAXReader (parser)
714 initAttrTable("value-of",
715 new String[] {"select", "disable-output-escaping"});
716 initAttrTable("element",
717 new String[] {"name", "namespace", "use-attribute-sets"});
718 initAttrTable("call-template", new String[] {"name"});
719 initAttrTable("apply-templates", new String[] {"select", "mode"});
720 initAttrTable("apply-imports", new String[] {});
721 initAttrTable("decimal-format",
722 new String[] {"name", "decimal-separator", "grouping-separator",
723 "infinity", "minus-sign", "NaN", "percent", "per-mille",
724 "zero-digit", "digit", "pattern-separator"});
725 initAttrTable("import", new String[] {"href"});
726 initAttrTable("include", new String[] {"href"});
727 initAttrTable("strip-space", new String[] {"elements"});
728 initAttrTable("preserve-space", new String[] {"elements"});
729 initAttrTable("processing-instruction", new String[] {"name"});
730 initAttrTable("namespace-alias",
731 new String[] {"stylesheet-prefix", "result-prefix"});
732 }
733
734
735
736 /**
737 * Initialize the _instructionClasses map, which maps XSL element
738 * names to Java classes in this package.
739 */
740 private void initStdClasses() {
741 initStdClass("template", "Template");
742 initStdClass("stylesheet", "Stylesheet");
743 initStdClass("transform", "Stylesheet");
744 initStdClass("text", "Text");
745 initStdClass("if", "If");
746 initStdClass("choose", "Choose");
747 initStdClass("when", "When");
748 initStdClass("otherwise", "Otherwise");
749 initStdClass("for-each", "ForEach");
750 initStdClass("message", "Message");
751 initStdClass("number", "Number");
752 initStdClass("comment", "Comment");
753 initStdClass("copy", "Copy");
754 initStdClass("copy-of", "CopyOf");
755 initStdClass("param", "Param");
789 }
790
791 private void initExtClasses() {
792 initExtClass("output", "TransletOutput");
793 initExtClass(REDIRECT_URI, "write", "TransletOutput");
794 }
795
796 private void initExtClass(String elementName, String className) {
797 _instructionClasses.put(getQName(TRANSLET_URI, TRANSLET, elementName).getStringRep(),
798 COMPILER_PACKAGE + '.' + className);
799 }
800
801 private void initExtClass(String namespace, String elementName, String className) {
802 _instructionClasses.put(getQName(namespace, TRANSLET, elementName).getStringRep(),
803 COMPILER_PACKAGE + '.' + className);
804 }
805
806 /**
807 * Add primops and base functions to the symbol table.
808 */
809 private void initSymbolTable() {
810 MethodType I_V = new MethodType(Type.Int, Type.Void);
811 MethodType I_R = new MethodType(Type.Int, Type.Real);
812 MethodType I_S = new MethodType(Type.Int, Type.String);
813 MethodType I_D = new MethodType(Type.Int, Type.NodeSet);
814 MethodType R_I = new MethodType(Type.Real, Type.Int);
815 MethodType R_V = new MethodType(Type.Real, Type.Void);
816 MethodType R_R = new MethodType(Type.Real, Type.Real);
817 MethodType R_D = new MethodType(Type.Real, Type.NodeSet);
818 MethodType R_O = new MethodType(Type.Real, Type.Reference);
819 MethodType I_I = new MethodType(Type.Int, Type.Int);
820 MethodType D_O = new MethodType(Type.NodeSet, Type.Reference);
821 MethodType D_V = new MethodType(Type.NodeSet, Type.Void);
822 MethodType D_S = new MethodType(Type.NodeSet, Type.String);
823 MethodType D_D = new MethodType(Type.NodeSet, Type.NodeSet);
824 MethodType A_V = new MethodType(Type.Node, Type.Void);
825 MethodType S_V = new MethodType(Type.String, Type.Void);
826 MethodType S_S = new MethodType(Type.String, Type.String);
827 MethodType S_A = new MethodType(Type.String, Type.Node);
828 MethodType S_D = new MethodType(Type.String, Type.NodeSet);
981 }
982
983 /**
984 * Creates a new node in the abstract syntax tree. This node can be
985 * o) a supported XSLT 1.0 element
986 * o) an unsupported XSLT element (post 1.0)
987 * o) a supported XSLT extension
988 * o) an unsupported XSLT extension
989 * o) a literal result element (not an XSLT element and not an extension)
990 * Unsupported elements do not directly generate an error. We have to wait
991 * until we have received all child elements of an unsupported element to
992 * see if any <xsl:fallback> elements exist.
993 */
994
995 private boolean versionIsOne = true;
996
997 public SyntaxTreeNode makeInstance(String uri, String prefix,
998 String local, Attributes attributes)
999 {
1000 SyntaxTreeNode node = null;
1001 QName qname = getQName(uri, prefix, local);
1002 String className = _instructionClasses.get(qname.getStringRep());
1003
1004 if (className != null) {
1005 try {
1006 final Class clazz = ObjectFactory.findProviderClass(className, true);
1007 node = (SyntaxTreeNode)clazz.newInstance();
1008 node.setQName(qname);
1009 node.setParser(this);
1010 if (_locator != null) {
1011 node.setLineNumber(getLineNumber());
1012 }
1013 if (node instanceof Stylesheet) {
1014 _xsltc.setStylesheet((Stylesheet)node);
1015 }
1016 checkForSuperfluousAttributes(node, attributes);
1017 }
1018 catch (ClassNotFoundException e) {
1019 ErrorMsg err = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, node);
1020 reportError(ERROR, err);
1021 }
1022 catch (Exception e) {
1023 ErrorMsg err = new ErrorMsg(ErrorMsg.INTERNAL_ERR,
1024 e.getMessage(), node);
1025 reportError(FATAL, err);
1026 }
1033 UnsupportedElement element = (UnsupportedElement)node;
1034 ErrorMsg msg = new ErrorMsg(ErrorMsg.UNSUPPORTED_XSL_ERR,
1035 getLineNumber(),local);
1036 element.setErrorMessage(msg);
1037 if (versionIsOne) {
1038 reportError(UNSUPPORTED,msg);
1039 }
1040 }
1041 // Check if this is an XSLTC extension element
1042 else if (uri.equals(TRANSLET_URI)) {
1043 node = new UnsupportedElement(uri, prefix, local, true);
1044 UnsupportedElement element = (UnsupportedElement)node;
1045 ErrorMsg msg = new ErrorMsg(ErrorMsg.UNSUPPORTED_EXT_ERR,
1046 getLineNumber(),local);
1047 element.setErrorMessage(msg);
1048 }
1049 // Check if this is an extension of some other XSLT processor
1050 else {
1051 Stylesheet sheet = _xsltc.getStylesheet();
1052 if ((sheet != null) && (sheet.isExtension(uri))) {
1053 if (sheet != (SyntaxTreeNode)_parentStack.peek()) {
1054 node = new UnsupportedElement(uri, prefix, local, true);
1055 UnsupportedElement elem = (UnsupportedElement)node;
1056 ErrorMsg msg =
1057 new ErrorMsg(ErrorMsg.UNSUPPORTED_EXT_ERR,
1058 getLineNumber(),
1059 prefix+":"+local);
1060 elem.setErrorMessage(msg);
1061 }
1062 }
1063 }
1064 }
1065 if (node == null) {
1066 node = new LiteralElement();
1067 node.setLineNumber(getLineNumber());
1068 }
1069 }
1070 if ((node != null) && (node instanceof LiteralElement)) {
1071 ((LiteralElement)node).setQName(qname);
1072 }
1073 return(node);
1166 return (Pattern)parseTopLevel(parent, "<PATTERN>"+pattern, pattern);
1167 }
1168
1169 /**
1170 * Parse an XPath expression or pattern using the generated XPathParser
1171 * The method will return a Dummy node if the XPath parser fails.
1172 */
1173 private SyntaxTreeNode parseTopLevel(SyntaxTreeNode parent, String text,
1174 String expression) {
1175 int line = getLineNumber();
1176
1177 try {
1178 _xpathParser.setScanner(new XPathLexer(new StringReader(text)));
1179 Symbol result = _xpathParser.parse(expression, line);
1180 if (result != null) {
1181 final SyntaxTreeNode node = (SyntaxTreeNode)result.value;
1182 if (node != null) {
1183 node.setParser(this);
1184 node.setParent(parent);
1185 node.setLineNumber(line);
1186 // System.out.println("e = " + text + " " + node);
1187 return node;
1188 }
1189 }
1190 reportError(ERROR, new ErrorMsg(ErrorMsg.XPATH_PARSER_ERR,
1191 expression, parent));
1192 }
1193 catch (Exception e) {
1194 if (_xsltc.debug()) e.printStackTrace();
1195 reportError(ERROR, new ErrorMsg(ErrorMsg.XPATH_PARSER_ERR,
1196 expression, parent));
1197 }
1198
1199 // Return a dummy pattern (which is an expression)
1200 SyntaxTreeNode.Dummy.setParser(this);
1201 return SyntaxTreeNode.Dummy;
1202 }
1203
1204 /************************ ERROR HANDLING SECTION ************************/
1205
1206 /**
1262 _errors.add(error);
1263 break;
1264 case Constants.WARNING:
1265 // Other error in the stylesheet input (content errors only)
1266 // Does not terminate compilation, a translet is produced
1267 _warnings.add(error);
1268 break;
1269 }
1270 }
1271
1272 public ArrayList<ErrorMsg> getErrors() {
1273 return _errors;
1274 }
1275
1276 public ArrayList<ErrorMsg> getWarnings() {
1277 return _warnings;
1278 }
1279
1280 /************************ SAX2 ContentHandler INTERFACE *****************/
1281
1282 private Stack _parentStack = null;
1283 private Map<String, String> _prefixMapping = null;
1284
1285 /**
1286 * SAX2: Receive notification of the beginning of a document.
1287 */
1288 public void startDocument() {
1289 _root = null;
1290 _target = null;
1291 _prefixMapping = null;
1292 _parentStack = new Stack();
1293 }
1294
1295 /**
1296 * SAX2: Receive notification of the end of a document.
1297 */
1298 public void endDocument() { }
1299
1300
1301 /**
1302 * SAX2: Begin the scope of a prefix-URI Namespace mapping.
1303 * This has to be passed on to the symbol table!
1304 */
1305 public void startPrefixMapping(String prefix, String uri) {
1306 if (_prefixMapping == null) {
1307 _prefixMapping = new HashMap<>();
1308 }
1309 _prefixMapping.put(prefix, uri);
1310 }
1311
1312 /**
1328
1329 SyntaxTreeNode element = makeInstance(uri, prefix,
1330 localname, attributes);
1331 if (element == null) {
1332 ErrorMsg err = new ErrorMsg(ErrorMsg.ELEMENT_PARSE_ERR,
1333 prefix+':'+localname);
1334 throw new SAXException(err.toString());
1335 }
1336
1337 // If this is the root element of the XML document we need to make sure
1338 // that it contains a definition of the XSL namespace URI
1339 if (_root == null) {
1340 if ((_prefixMapping == null) ||
1341 (_prefixMapping.containsValue(Constants.XSLT_URI) == false))
1342 _rootNamespaceDef = false;
1343 else
1344 _rootNamespaceDef = true;
1345 _root = element;
1346 }
1347 else {
1348 SyntaxTreeNode parent = (SyntaxTreeNode)_parentStack.peek();
1349 parent.addElement(element);
1350 element.setParent(parent);
1351 }
1352 element.setAttributes(new AttributesImpl(attributes));
1353 element.setPrefixMapping(_prefixMapping);
1354
1355 if (element instanceof Stylesheet) {
1356 // Extension elements and excluded elements have to be
1357 // handled at this point in order to correctly generate
1358 // Fallback elements from <xsl:fallback>s.
1359 getSymbolTable().setCurrentNode(element);
1360 ((Stylesheet)element).declareExtensionPrefixes(this);
1361 }
1362
1363 _prefixMapping = null;
1364 _parentStack.push(element);
1365 }
1366
1367 /**
1368 * SAX2: Receive notification of the end of an element.
1369 */
1370 public void endElement(String uri, String localname, String qname) {
1371 _parentStack.pop();
1372 }
1373
1374 /**
1375 * SAX2: Receive notification of character data.
1376 */
1377 public void characters(char[] ch, int start, int length) {
1378 String string = new String(ch, start, length);
1379 SyntaxTreeNode parent = (SyntaxTreeNode)_parentStack.peek();
1380
1381 if (string.length() == 0) return;
1382
1383 // If this text occurs within an <xsl:text> element we append it
1384 // as-is to the existing text element
1385 if (parent instanceof Text) {
1386 ((Text)parent).setText(string);
1387 return;
1388 }
1389
1390 // Ignore text nodes that occur directly under <xsl:stylesheet>
1391 if (parent instanceof Stylesheet) return;
1392
1393 SyntaxTreeNode bro = parent.lastChild();
1394 if ((bro != null) && (bro instanceof Text)) {
1395 Text text = (Text)bro;
1396 if (!text.isTextElement()) {
1397 if ((length > 1) || ( ((int)ch[0]) < 0x100)) {
1398 text.setText(string);
1399 return;
|
1 /*
2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one or more
6 * contributor license agreements. See the NOTICE file distributed with
7 * this work for additional information regarding copyright ownership.
8 * The ASF licenses this file to You under the Apache License, Version 2.0
9 * (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 package com.sun.org.apache.xalan.internal.xsltc.compiler;
22
23 import com.sun.java_cup.internal.runtime.Symbol;
24 import com.sun.org.apache.xalan.internal.XalanConstants;
25 import com.sun.org.apache.xalan.internal.utils.FactoryImpl;
26 import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
27 import com.sun.org.apache.xalan.internal.utils.SecuritySupport;
28 import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager;
29 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
33 import com.sun.org.apache.xml.internal.serializer.utils.SystemIDResolver;
34 import java.io.File;
35 import java.io.IOException;
36 import java.io.StringReader;
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.Iterator;
52 import org.xml.sax.Attributes;
53 import org.xml.sax.ContentHandler;
54 import org.xml.sax.InputSource;
55 import org.xml.sax.Locator;
56 import org.xml.sax.SAXException;
57 import org.xml.sax.SAXNotRecognizedException;
58 import org.xml.sax.SAXNotSupportedException;
59 import org.xml.sax.SAXParseException;
60 import org.xml.sax.XMLReader;
61 import org.xml.sax.helpers.AttributesImpl;
62
63 /**
64 * @author Jacek Ambroziak
65 * @author Santiago Pericas-Geertsen
66 * @author G. Todd Miller
67 * @author Morten Jorgensen
68 * @author Erwin Bolwidt <ejb@klomp.org>
69 */
70 public class Parser implements Constants, ContentHandler {
71
72 private static final String XSL = "xsl"; // standard prefix
73 private static final String TRANSLET = "translet"; // extension prefix
74
75 private Locator _locator = null;
76
77 private XSLTC _xsltc; // Reference to the compiler object.
78 private XPathParser _xpathParser; // Reference to the XPath parser.
79 private ArrayList<ErrorMsg> _errors; // Contains all compilation errors
80 private ArrayList<ErrorMsg> _warnings; // Contains all compilation warnings
81
82 private Map<String, String> _instructionClasses; // Maps instructions to classes
83 private Map<String, String[]> _instructionAttrs; // reqd and opt attrs
84 private Map<String, QName> _qNames;
85 private Map<String, Map<String, QName>> _namespaces;
86 private QName _useAttributeSets;
87 private QName _excludeResultPrefixes;
88 private QName _extensionElementPrefixes;
89 private Map<String, Object> _variableScope;
90 private Stylesheet _currentStylesheet;
91 private SymbolTable _symbolTable; // Maps QNames to syntax-tree nodes
92 private Output _output;
93 private Template _template; // Reference to the template being parsed.
94
95 private boolean _rootNamespaceDef; // Used for validity check
96
97 private SyntaxTreeNode _root;
98
99 private String _target;
100
101 private int _currentImportPrecedence;
102
103 private boolean _useServicesMechanism = true;
104
105 public Parser(XSLTC xsltc, boolean useServicesMechanism) {
123 _root = null;
124 _rootNamespaceDef = false;
125 _currentImportPrecedence = 1;
126
127 initStdClasses();
128 initInstructionAttrs();
129 initExtClasses();
130 initSymbolTable();
131
132 _useAttributeSets =
133 getQName(XSLT_URI, XSL, "use-attribute-sets");
134 _excludeResultPrefixes =
135 getQName(XSLT_URI, XSL, "exclude-result-prefixes");
136 _extensionElementPrefixes =
137 getQName(XSLT_URI, XSL, "extension-element-prefixes");
138 }
139
140 public void setOutput(Output output) {
141 if (_output != null) {
142 if (_output.getImportPrecedence() <= output.getImportPrecedence()) {
143 output.mergeOutput(_output);
144 _output.disable();
145 _output = output;
146 }
147 else {
148 output.disable();
149 }
150 }
151 else {
152 _output = output;
153 }
154 }
155
156 public Output getOutput() {
157 return _output;
158 }
159
160 public Properties getOutputProperties() {
161 return getTopLevelStylesheet().getOutputProperties();
162 }
163
164 public void addVariable(Variable var) {
165 addVariableOrParam(var);
166 }
167
168 public void addParameter(Param param) {
169 addVariableOrParam(param);
170 }
171
172 private void addVariableOrParam(VariableBase var) {
173 Object existing = _variableScope.get(var.getName().getStringRep());
174 if (existing != null) {
175 if (existing instanceof Stack) {
176 @SuppressWarnings("unchecked")
177 Stack<VariableBase> stack = (Stack<VariableBase>)existing;
178 stack.push(var);
179 }
180 else if (existing instanceof VariableBase) {
181 Stack<VariableBase> stack = new Stack<>();
182 stack.push((VariableBase)existing);
183 stack.push(var);
184 _variableScope.put(var.getName().getStringRep(), stack);
185 }
186 }
187 else {
188 _variableScope.put(var.getName().getStringRep(), var);
189 }
190 }
191
192 public void removeVariable(QName name) {
193 Object existing = _variableScope.get(name.getStringRep());
194 if (existing instanceof Stack) {
195 @SuppressWarnings("unchecked")
196 Stack<VariableBase> stack = (Stack<VariableBase>)existing;
197 if (!stack.isEmpty()) stack.pop();
198 if (!stack.isEmpty()) return;
199 }
200 _variableScope.remove(name.getStringRep());
201 }
202
203 public VariableBase lookupVariable(QName name) {
204 Object existing = _variableScope.get(name.getStringRep());
205 if (existing instanceof VariableBase) {
206 return (VariableBase)existing;
207 }
208 else if (existing instanceof Stack) {
209 @SuppressWarnings("unchecked")
210 Stack<VariableBase> stack = (Stack<VariableBase>)existing;
211 return stack.peek();
212 }
213 return null;
214 }
215
216 public void setXSLTC(XSLTC xsltc) {
217 _xsltc = xsltc;
218 }
219
220 public XSLTC getXSLTC() {
221 return _xsltc;
222 }
223
224 public int getCurrentImportPrecedence() {
225 return _currentImportPrecedence;
226 }
227
228 public int getNextImportPrecedence() {
229 return ++_currentImportPrecedence;
230 }
231
232 public void setCurrentStylesheet(Stylesheet stylesheet) {
233 _currentStylesheet = stylesheet;
383 if (element.lookupNamespace(EMPTYSTRING) == null) {
384 element.addPrefixMapping(EMPTYSTRING, EMPTYSTRING);
385 }
386 }
387 stylesheet.setParser(this);
388 return stylesheet;
389 }
390 catch (ClassCastException e) {
391 ErrorMsg err = new ErrorMsg(ErrorMsg.NOT_STYLESHEET_ERR, element);
392 throw new CompilerException(err.toString());
393 }
394 }
395
396 /**
397 * Instanciates a SAX2 parser and generate the AST from the input.
398 */
399 public void createAST(Stylesheet stylesheet) {
400 try {
401 if (stylesheet != null) {
402 stylesheet.parseContents(this);
403 final Iterator<SyntaxTreeNode> elements = stylesheet.elements();
404 while (elements.hasNext()) {
405 SyntaxTreeNode child = elements.next();
406 if (child instanceof Text) {
407 final int l = getLineNumber();
408 ErrorMsg err =
409 new ErrorMsg(ErrorMsg.ILLEGAL_TEXT_NODE_ERR,l,null);
410 reportError(ERROR, err);
411 }
412 }
413 if (!errorsFound()) {
414 stylesheet.typeCheck(_symbolTable);
415 }
416 }
417 }
418 catch (TypeCheckError e) {
419 reportError(ERROR, new ErrorMsg(ErrorMsg.JAXP_COMPILE_ERR, e));
420 }
421 }
422
423 /**
424 * Parses a stylesheet and builds the internal abstract syntax tree
425 * @param reader A SAX2 SAXReader (parser)
712 initAttrTable("value-of",
713 new String[] {"select", "disable-output-escaping"});
714 initAttrTable("element",
715 new String[] {"name", "namespace", "use-attribute-sets"});
716 initAttrTable("call-template", new String[] {"name"});
717 initAttrTable("apply-templates", new String[] {"select", "mode"});
718 initAttrTable("apply-imports", new String[] {});
719 initAttrTable("decimal-format",
720 new String[] {"name", "decimal-separator", "grouping-separator",
721 "infinity", "minus-sign", "NaN", "percent", "per-mille",
722 "zero-digit", "digit", "pattern-separator"});
723 initAttrTable("import", new String[] {"href"});
724 initAttrTable("include", new String[] {"href"});
725 initAttrTable("strip-space", new String[] {"elements"});
726 initAttrTable("preserve-space", new String[] {"elements"});
727 initAttrTable("processing-instruction", new String[] {"name"});
728 initAttrTable("namespace-alias",
729 new String[] {"stylesheet-prefix", "result-prefix"});
730 }
731
732 /**
733 * Initialize the _instructionClasses map, which maps XSL element
734 * names to Java classes in this package.
735 */
736 private void initStdClasses() {
737 initStdClass("template", "Template");
738 initStdClass("stylesheet", "Stylesheet");
739 initStdClass("transform", "Stylesheet");
740 initStdClass("text", "Text");
741 initStdClass("if", "If");
742 initStdClass("choose", "Choose");
743 initStdClass("when", "When");
744 initStdClass("otherwise", "Otherwise");
745 initStdClass("for-each", "ForEach");
746 initStdClass("message", "Message");
747 initStdClass("number", "Number");
748 initStdClass("comment", "Comment");
749 initStdClass("copy", "Copy");
750 initStdClass("copy-of", "CopyOf");
751 initStdClass("param", "Param");
785 }
786
787 private void initExtClasses() {
788 initExtClass("output", "TransletOutput");
789 initExtClass(REDIRECT_URI, "write", "TransletOutput");
790 }
791
792 private void initExtClass(String elementName, String className) {
793 _instructionClasses.put(getQName(TRANSLET_URI, TRANSLET, elementName).getStringRep(),
794 COMPILER_PACKAGE + '.' + className);
795 }
796
797 private void initExtClass(String namespace, String elementName, String className) {
798 _instructionClasses.put(getQName(namespace, TRANSLET, elementName).getStringRep(),
799 COMPILER_PACKAGE + '.' + className);
800 }
801
802 /**
803 * Add primops and base functions to the symbol table.
804 */
805 @SuppressWarnings("unused")
806 private void initSymbolTable() {
807 MethodType I_V = new MethodType(Type.Int, Type.Void);
808 MethodType I_R = new MethodType(Type.Int, Type.Real);
809 MethodType I_S = new MethodType(Type.Int, Type.String);
810 MethodType I_D = new MethodType(Type.Int, Type.NodeSet);
811 MethodType R_I = new MethodType(Type.Real, Type.Int);
812 MethodType R_V = new MethodType(Type.Real, Type.Void);
813 MethodType R_R = new MethodType(Type.Real, Type.Real);
814 MethodType R_D = new MethodType(Type.Real, Type.NodeSet);
815 MethodType R_O = new MethodType(Type.Real, Type.Reference);
816 MethodType I_I = new MethodType(Type.Int, Type.Int);
817 MethodType D_O = new MethodType(Type.NodeSet, Type.Reference);
818 MethodType D_V = new MethodType(Type.NodeSet, Type.Void);
819 MethodType D_S = new MethodType(Type.NodeSet, Type.String);
820 MethodType D_D = new MethodType(Type.NodeSet, Type.NodeSet);
821 MethodType A_V = new MethodType(Type.Node, Type.Void);
822 MethodType S_V = new MethodType(Type.String, Type.Void);
823 MethodType S_S = new MethodType(Type.String, Type.String);
824 MethodType S_A = new MethodType(Type.String, Type.Node);
825 MethodType S_D = new MethodType(Type.String, Type.NodeSet);
978 }
979
980 /**
981 * Creates a new node in the abstract syntax tree. This node can be
982 * o) a supported XSLT 1.0 element
983 * o) an unsupported XSLT element (post 1.0)
984 * o) a supported XSLT extension
985 * o) an unsupported XSLT extension
986 * o) a literal result element (not an XSLT element and not an extension)
987 * Unsupported elements do not directly generate an error. We have to wait
988 * until we have received all child elements of an unsupported element to
989 * see if any <xsl:fallback> elements exist.
990 */
991
992 private boolean versionIsOne = true;
993
994 public SyntaxTreeNode makeInstance(String uri, String prefix,
995 String local, Attributes attributes)
996 {
997 SyntaxTreeNode node = null;
998 QName qname = getQName(uri, prefix, local);
999 String className = _instructionClasses.get(qname.getStringRep());
1000
1001 if (className != null) {
1002 try {
1003 final Class<?> clazz = ObjectFactory.findProviderClass(className, true);
1004 node = (SyntaxTreeNode)clazz.newInstance();
1005 node.setQName(qname);
1006 node.setParser(this);
1007 if (_locator != null) {
1008 node.setLineNumber(getLineNumber());
1009 }
1010 if (node instanceof Stylesheet) {
1011 _xsltc.setStylesheet((Stylesheet)node);
1012 }
1013 checkForSuperfluousAttributes(node, attributes);
1014 }
1015 catch (ClassNotFoundException e) {
1016 ErrorMsg err = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, node);
1017 reportError(ERROR, err);
1018 }
1019 catch (Exception e) {
1020 ErrorMsg err = new ErrorMsg(ErrorMsg.INTERNAL_ERR,
1021 e.getMessage(), node);
1022 reportError(FATAL, err);
1023 }
1030 UnsupportedElement element = (UnsupportedElement)node;
1031 ErrorMsg msg = new ErrorMsg(ErrorMsg.UNSUPPORTED_XSL_ERR,
1032 getLineNumber(),local);
1033 element.setErrorMessage(msg);
1034 if (versionIsOne) {
1035 reportError(UNSUPPORTED,msg);
1036 }
1037 }
1038 // Check if this is an XSLTC extension element
1039 else if (uri.equals(TRANSLET_URI)) {
1040 node = new UnsupportedElement(uri, prefix, local, true);
1041 UnsupportedElement element = (UnsupportedElement)node;
1042 ErrorMsg msg = new ErrorMsg(ErrorMsg.UNSUPPORTED_EXT_ERR,
1043 getLineNumber(),local);
1044 element.setErrorMessage(msg);
1045 }
1046 // Check if this is an extension of some other XSLT processor
1047 else {
1048 Stylesheet sheet = _xsltc.getStylesheet();
1049 if ((sheet != null) && (sheet.isExtension(uri))) {
1050 if (sheet != _parentStack.peek()) {
1051 node = new UnsupportedElement(uri, prefix, local, true);
1052 UnsupportedElement elem = (UnsupportedElement)node;
1053 ErrorMsg msg =
1054 new ErrorMsg(ErrorMsg.UNSUPPORTED_EXT_ERR,
1055 getLineNumber(),
1056 prefix+":"+local);
1057 elem.setErrorMessage(msg);
1058 }
1059 }
1060 }
1061 }
1062 if (node == null) {
1063 node = new LiteralElement();
1064 node.setLineNumber(getLineNumber());
1065 }
1066 }
1067 if ((node != null) && (node instanceof LiteralElement)) {
1068 ((LiteralElement)node).setQName(qname);
1069 }
1070 return(node);
1163 return (Pattern)parseTopLevel(parent, "<PATTERN>"+pattern, pattern);
1164 }
1165
1166 /**
1167 * Parse an XPath expression or pattern using the generated XPathParser
1168 * The method will return a Dummy node if the XPath parser fails.
1169 */
1170 private SyntaxTreeNode parseTopLevel(SyntaxTreeNode parent, String text,
1171 String expression) {
1172 int line = getLineNumber();
1173
1174 try {
1175 _xpathParser.setScanner(new XPathLexer(new StringReader(text)));
1176 Symbol result = _xpathParser.parse(expression, line);
1177 if (result != null) {
1178 final SyntaxTreeNode node = (SyntaxTreeNode)result.value;
1179 if (node != null) {
1180 node.setParser(this);
1181 node.setParent(parent);
1182 node.setLineNumber(line);
1183 return node;
1184 }
1185 }
1186 reportError(ERROR, new ErrorMsg(ErrorMsg.XPATH_PARSER_ERR,
1187 expression, parent));
1188 }
1189 catch (Exception e) {
1190 if (_xsltc.debug()) e.printStackTrace();
1191 reportError(ERROR, new ErrorMsg(ErrorMsg.XPATH_PARSER_ERR,
1192 expression, parent));
1193 }
1194
1195 // Return a dummy pattern (which is an expression)
1196 SyntaxTreeNode.Dummy.setParser(this);
1197 return SyntaxTreeNode.Dummy;
1198 }
1199
1200 /************************ ERROR HANDLING SECTION ************************/
1201
1202 /**
1258 _errors.add(error);
1259 break;
1260 case Constants.WARNING:
1261 // Other error in the stylesheet input (content errors only)
1262 // Does not terminate compilation, a translet is produced
1263 _warnings.add(error);
1264 break;
1265 }
1266 }
1267
1268 public ArrayList<ErrorMsg> getErrors() {
1269 return _errors;
1270 }
1271
1272 public ArrayList<ErrorMsg> getWarnings() {
1273 return _warnings;
1274 }
1275
1276 /************************ SAX2 ContentHandler INTERFACE *****************/
1277
1278 private Stack<SyntaxTreeNode> _parentStack = null;
1279 private Map<String, String> _prefixMapping = null;
1280
1281 /**
1282 * SAX2: Receive notification of the beginning of a document.
1283 */
1284 public void startDocument() {
1285 _root = null;
1286 _target = null;
1287 _prefixMapping = null;
1288 _parentStack = new Stack<>();
1289 }
1290
1291 /**
1292 * SAX2: Receive notification of the end of a document.
1293 */
1294 public void endDocument() { }
1295
1296
1297 /**
1298 * SAX2: Begin the scope of a prefix-URI Namespace mapping.
1299 * This has to be passed on to the symbol table!
1300 */
1301 public void startPrefixMapping(String prefix, String uri) {
1302 if (_prefixMapping == null) {
1303 _prefixMapping = new HashMap<>();
1304 }
1305 _prefixMapping.put(prefix, uri);
1306 }
1307
1308 /**
1324
1325 SyntaxTreeNode element = makeInstance(uri, prefix,
1326 localname, attributes);
1327 if (element == null) {
1328 ErrorMsg err = new ErrorMsg(ErrorMsg.ELEMENT_PARSE_ERR,
1329 prefix+':'+localname);
1330 throw new SAXException(err.toString());
1331 }
1332
1333 // If this is the root element of the XML document we need to make sure
1334 // that it contains a definition of the XSL namespace URI
1335 if (_root == null) {
1336 if ((_prefixMapping == null) ||
1337 (_prefixMapping.containsValue(Constants.XSLT_URI) == false))
1338 _rootNamespaceDef = false;
1339 else
1340 _rootNamespaceDef = true;
1341 _root = element;
1342 }
1343 else {
1344 SyntaxTreeNode parent = _parentStack.peek();
1345 parent.addElement(element);
1346 element.setParent(parent);
1347 }
1348 element.setAttributes(new AttributesImpl(attributes));
1349 element.setPrefixMapping(_prefixMapping);
1350
1351 if (element instanceof Stylesheet) {
1352 // Extension elements and excluded elements have to be
1353 // handled at this point in order to correctly generate
1354 // Fallback elements from <xsl:fallback>s.
1355 getSymbolTable().setCurrentNode(element);
1356 ((Stylesheet)element).declareExtensionPrefixes(this);
1357 }
1358
1359 _prefixMapping = null;
1360 _parentStack.push(element);
1361 }
1362
1363 /**
1364 * SAX2: Receive notification of the end of an element.
1365 */
1366 public void endElement(String uri, String localname, String qname) {
1367 _parentStack.pop();
1368 }
1369
1370 /**
1371 * SAX2: Receive notification of character data.
1372 */
1373 public void characters(char[] ch, int start, int length) {
1374 String string = new String(ch, start, length);
1375 SyntaxTreeNode parent = _parentStack.peek();
1376
1377 if (string.length() == 0) return;
1378
1379 // If this text occurs within an <xsl:text> element we append it
1380 // as-is to the existing text element
1381 if (parent instanceof Text) {
1382 ((Text)parent).setText(string);
1383 return;
1384 }
1385
1386 // Ignore text nodes that occur directly under <xsl:stylesheet>
1387 if (parent instanceof Stylesheet) return;
1388
1389 SyntaxTreeNode bro = parent.lastChild();
1390 if ((bro != null) && (bro instanceof Text)) {
1391 Text text = (Text)bro;
1392 if (!text.isTextElement()) {
1393 if ((length > 1) || ( ((int)ch[0]) < 0x100)) {
1394 text.setText(string);
1395 return;
|