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