1 /*
2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
3 * @LastModified: Oct 2017
4 */
5 /*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements. See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21 /*
22 * $Id: XslAttribute.java,v 1.2.4.1 2005/09/12 11:39:32 pvedula Exp $
23 */
24
25 package com.sun.org.apache.xalan.internal.xsltc.compiler;
26
27 import com.sun.org.apache.bcel.internal.generic.ALOAD;
28 import com.sun.org.apache.bcel.internal.generic.ASTORE;
29 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
30 import com.sun.org.apache.bcel.internal.generic.GETFIELD;
31 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
32 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
33 import com.sun.org.apache.bcel.internal.generic.InstructionList;
34 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
35 import com.sun.org.apache.bcel.internal.generic.PUSH;
36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
37 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
41 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
42 import com.sun.org.apache.xml.internal.serializer.ElemDesc;
43 import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
44 import com.sun.org.apache.xml.internal.utils.XML11Char;
45 import java.util.List;
46
47 /**
48 * @author Jacek Ambroziak
49 * @author Santiago Pericas-Geertsen
50 * @author Morten Jorgensen
51 * @author Erwin Bolwidt <ejb@klomp.org>
52 * @author Gunnlaugur Briem <gthb@dimon.is>
53 */
54 final class XslAttribute extends Instruction {
55
56 private String _prefix;
57 private AttributeValue _name; // name treated as AVT (7.1.3)
58 private AttributeValueTemplate _namespace = null;
59 private boolean _ignore = false;
60 private boolean _isLiteral = false; // specified name is not AVT
61
62 /**
63 * Returns the name of the attribute
64 */
65 public AttributeValue getName() {
66 return _name;
67 }
68
69 /**
70 * Displays the contents of the attribute
71 */
72 public void display(int indent) {
73 indent(indent);
74 Util.println("Attribute " + _name);
75 displayContents(indent + IndentIncrement);
76 }
77
78 /**
79 * Parses the attribute's contents. Special care taken for namespaces.
80 */
81 public void parseContents(Parser parser) {
82 boolean generated = false;
83 final SymbolTable stable = parser.getSymbolTable();
84
85 String name = getAttribute("name");
86 String namespace = getAttribute("namespace");
87 QName qname = parser.getQName(name, false);
88 final String prefix = qname.getPrefix();
89
90 if (((prefix != null) && (prefix.equals(XMLNS_PREFIX)))||(name.equals(XMLNS_PREFIX))) {
91 reportError(this, parser, ErrorMsg.ILLEGAL_ATTR_NAME_ERR, name);
92 return;
93 }
94
95 _isLiteral = Util.isLiteral(name);
96 if (_isLiteral) {
97 if (!XML11Char.isXML11ValidQName(name)) {
98 reportError(this, parser, ErrorMsg.ILLEGAL_ATTR_NAME_ERR, name);
99 return;
100 }
101 }
102
103 // Ignore attribute if preceeded by some other type of element
104 final SyntaxTreeNode parent = getParent();
105 final List<SyntaxTreeNode> siblings = parent.getContents();
106 for (int i = 0; i < parent.elementCount(); i++) {
107 SyntaxTreeNode item = siblings.get(i);
108 if (item == this) break;
109
110 // These three objects result in one or more attribute output
111 if (item instanceof XslAttribute) continue;
112 if (item instanceof UseAttributeSets) continue;
113 if (item instanceof LiteralAttribute) continue;
114 if (item instanceof Text) continue;
115
116 // These objects _can_ result in one or more attribute
117 // The output handler will generate an error if not (at runtime)
118 if (item instanceof If) continue;
119 if (item instanceof Choose) continue;
120 if (item instanceof CopyOf) continue;
121 if (item instanceof VariableBase) continue;
122
123 // Report warning but do not ignore attribute
124 reportWarning(this, parser, ErrorMsg.STRAY_ATTRIBUTE_ERR, name);
125 }
126
127 // Get namespace from namespace attribute?
128 if (namespace != null && namespace != Constants.EMPTYSTRING) {
129 _prefix = lookupPrefix(namespace);
130 _namespace = new AttributeValueTemplate(namespace, parser, this);
131 }
132 // Get namespace from prefix in name attribute?
133 else if (prefix != null && prefix != Constants.EMPTYSTRING) {
134 _prefix = prefix;
135 namespace = lookupNamespace(prefix);
136 if (namespace != null) {
137 _namespace = new AttributeValueTemplate(namespace, parser, this);
138 }
139 }
140
141 // Common handling for namespaces:
142 if (_namespace != null) {
143 // Generate prefix if we have none
144 if (_prefix == null || _prefix == Constants.EMPTYSTRING) {
145 if (prefix != null) {
146 _prefix = prefix;
147 }
148 else {
149 _prefix = stable.generateNamespacePrefix();
150 generated = true;
151 }
152 }
153 else if (prefix != null && !prefix.equals(_prefix)) {
154 _prefix = prefix;
155 }
156
157 name = _prefix + ":" + qname.getLocalPart();
158
159 /*
160 * TODO: The namespace URI must be passed to the parent
161 * element but we don't yet know what the actual URI is
162 * (as we only know it as an attribute value template).
163 */
164 if ((parent instanceof LiteralElement) && (!generated)) {
165 ((LiteralElement)parent).registerNamespace(_prefix,
166 namespace,
167 stable, false);
168 }
169 }
170
171 if (parent instanceof LiteralElement) {
172 ((LiteralElement)parent).addAttribute(this);
173 }
174
175 _name = AttributeValue.create(this, name, parser);
176 parseChildren(parser);
177 }
178
179 public Type typeCheck(SymbolTable stable) throws TypeCheckError {
180 if (!_ignore) {
181 _name.typeCheck(stable);
182 if (_namespace != null) {
183 _namespace.typeCheck(stable);
184 }
185 typeCheckContents(stable);
186 }
187 return Type.Void;
188 }
189
190 /**
191 *
192 */
193 public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
194 final ConstantPoolGen cpg = classGen.getConstantPool();
195 final InstructionList il = methodGen.getInstructionList();
196
197 if (_ignore) return;
198 _ignore = true;
199
200 // Compile code that emits any needed namespace declaration
201 if (_namespace != null) {
202 // public void attribute(final String name, final String value)
203 il.append(methodGen.loadHandler());
204 il.append(new PUSH(cpg,_prefix));
205 _namespace.translate(classGen,methodGen);
206 il.append(methodGen.namespace());
207 }
208
209 if (!_isLiteral) {
210 // if the qname is an AVT, then the qname has to be checked at runtime if it is a valid qname
211 LocalVariableGen nameValue =
212 methodGen.addLocalVariable2("nameValue",
213 Util.getJCRefType(STRING_SIG),
214 null);
215
216 // store the name into a variable first so _name.translate only needs to be called once
217 _name.translate(classGen, methodGen);
218 nameValue.setStart(il.append(new ASTORE(nameValue.getIndex())));
219 il.append(new ALOAD(nameValue.getIndex()));
220
221 // call checkQName if the name is an AVT
222 final int check = cpg.addMethodref(BASIS_LIBRARY_CLASS, "checkAttribQName",
223 "("
224 +STRING_SIG
225 +")V");
226 il.append(new INVOKESTATIC(check));
227
228 // Save the current handler base on the stack
229 il.append(methodGen.loadHandler());
230 il.append(DUP); // first arg to "attributes" call
231
232 // load name value again
233 nameValue.setEnd(il.append(new ALOAD(nameValue.getIndex())));
234 } else {
235 // Save the current handler base on the stack
236 il.append(methodGen.loadHandler());
237 il.append(DUP); // first arg to "attributes" call
238
239 // Push attribute name
240 _name.translate(classGen, methodGen);// 2nd arg
241
242 }
243
244 // Push attribute value - shortcut for literal strings
245 if ((elementCount() == 1) && (elementAt(0) instanceof Text)) {
246 il.append(new PUSH(cpg, ((Text)elementAt(0)).getText()));
247 }
248 else {
249 il.append(classGen.loadTranslet());
250 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
251 "stringValueHandler",
252 STRING_VALUE_HANDLER_SIG)));
253 il.append(DUP);
254 il.append(methodGen.storeHandler());
255 // translate contents with substituted handler
256 translateContents(classGen, methodGen);
257 // get String out of the handler
258 il.append(new INVOKEVIRTUAL(cpg.addMethodref(STRING_VALUE_HANDLER,
259 "getValue",
260 "()" + STRING_SIG)));
261 }
262
263 SyntaxTreeNode parent = getParent();
264 if (parent instanceof LiteralElement
265 && ((LiteralElement)parent).allAttributesUnique()) {
266 int flags = 0;
267 ElemDesc elemDesc = ((LiteralElement)parent).getElemDesc();
268
269 // Set the HTML flags
270 if (elemDesc != null && _name instanceof SimpleAttributeValue) {
271 String attrName = ((SimpleAttributeValue)_name).toString();
272 if (elemDesc.isAttrFlagSet(attrName, ElemDesc.ATTREMPTY)) {
273 flags = flags | SerializationHandler.HTML_ATTREMPTY;
274 }
275 else if (elemDesc.isAttrFlagSet(attrName, ElemDesc.ATTRURL)) {
276 flags = flags | SerializationHandler.HTML_ATTRURL;
277 }
278 }
279 il.append(new PUSH(cpg, flags));
280 il.append(methodGen.uniqueAttribute());
281 }
282 else {
283 // call "attribute"
284 il.append(methodGen.attribute());
285 }
286
287 // Restore old handler base from stack
288 il.append(methodGen.storeHandler());
289
290
291
292 }
293
294 }
--- EOF ---