001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: AttributeSet.java 468650 2006-10-28 07:03:30Z minchau $
020 */
021
022 package org.apache.xalan.xsltc.compiler;
023
024 import java.util.Enumeration;
025 import java.util.Vector;
026
027 import org.apache.bcel.generic.ConstantPoolGen;
028 import org.apache.bcel.generic.INVOKESPECIAL;
029 import org.apache.bcel.generic.InstructionList;
030 import org.apache.xalan.xsltc.compiler.util.AttributeSetMethodGenerator;
031 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
032 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
033 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
034 import org.apache.xalan.xsltc.compiler.util.Type;
035 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
036 import org.apache.xalan.xsltc.compiler.util.Util;
037 import org.apache.xml.utils.XML11Char;
038
039 /**
040 * @author Jacek Ambroziak
041 * @author Santiago Pericas-Geertsen
042 * @author Morten Jorgensen
043 */
044 final class AttributeSet extends TopLevelElement {
045
046 // This prefix is used for the method name of attribute set methods
047 private static final String AttributeSetPrefix = "$as$";
048
049 // Element contents
050 private QName _name;
051 private UseAttributeSets _useSets;
052 private AttributeSet _mergeSet;
053 private String _method;
054 private boolean _ignore = false;
055
056 /**
057 * Returns the QName of this attribute set
058 */
059 public QName getName() {
060 return _name;
061 }
062
063 /**
064 * Returns the method name of this attribute set. This method name is
065 * generated by the compiler (XSLTC)
066 */
067 public String getMethodName() {
068 return _method;
069 }
070
071 /**
072 * Call this method to prevent a method for being compiled for this set.
073 * This is used in case several <xsl:attribute-set...> elements constitute
074 * a single set (with one name). The last element will merge itself with
075 * any previous set(s) with the same name and disable the other set(s).
076 */
077 public void ignore() {
078 _ignore = true;
079 }
080
081 /**
082 * Parse the contents of this attribute set. Recognised attributes are
083 * "name" (required) and "use-attribute-sets" (optional).
084 */
085 public void parseContents(Parser parser) {
086
087 // Get this attribute set's name
088 final String name = getAttribute("name");
089
090 if (!XML11Char.isXML11ValidQName(name)) {
091 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
092 parser.reportError(Constants.ERROR, err);
093 }
094 _name = parser.getQNameIgnoreDefaultNs(name);
095 if ((_name == null) || (_name.equals(EMPTYSTRING))) {
096 ErrorMsg msg = new ErrorMsg(ErrorMsg.UNNAMED_ATTRIBSET_ERR, this);
097 parser.reportError(Constants.ERROR, msg);
098 }
099
100 // Get any included attribute sets (similar to inheritance...)
101 final String useSets = getAttribute("use-attribute-sets");
102 if (useSets.length() > 0) {
103 if (!Util.isValidQNames(useSets)) {
104 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, useSets, this);
105 parser.reportError(Constants.ERROR, err);
106 }
107 _useSets = new UseAttributeSets(useSets, parser);
108 }
109
110 // Parse the contents of this node. All child elements must be
111 // <xsl:attribute> elements. Other elements cause an error.
112 final Vector contents = getContents();
113 final int count = contents.size();
114 for (int i=0; i<count; i++) {
115 SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
116 if (child instanceof XslAttribute) {
117 parser.getSymbolTable().setCurrentNode(child);
118 child.parseContents(parser);
119 }
120 else if (child instanceof Text) {
121 // ignore
122 }
123 else {
124 ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_CHILD_ERR, this);
125 parser.reportError(Constants.ERROR, msg);
126 }
127 }
128
129 // Point the symbol table back at us...
130 parser.getSymbolTable().setCurrentNode(this);
131 }
132
133 /**
134 * Type check the contents of this element
135 */
136 public Type typeCheck(SymbolTable stable) throws TypeCheckError {
137
138 if (_ignore) return (Type.Void);
139
140 // _mergeSet Point to any previous definition of this attribute set
141 _mergeSet = stable.addAttributeSet(this);
142
143 _method = AttributeSetPrefix + getXSLTC().nextAttributeSetSerial();
144
145 if (_useSets != null) _useSets.typeCheck(stable);
146 typeCheckContents(stable);
147 return Type.Void;
148 }
149
150 /**
151 * Compile a method that outputs the attributes in this set
152 */
153 public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
154
155 if (_ignore) return;
156
157 // Create a new method generator for an attribute set method
158 methodGen = new AttributeSetMethodGenerator(_method, classGen);
159
160 // Generate a reference to previous attribute-set definitions with the
161 // same name first. Those later in the stylesheet take precedence.
162 if (_mergeSet != null) {
163 final ConstantPoolGen cpg = classGen.getConstantPool();
164 final InstructionList il = methodGen.getInstructionList();
165 final String methodName = _mergeSet.getMethodName();
166
167 il.append(classGen.loadTranslet());
168 il.append(methodGen.loadDOM());
169 il.append(methodGen.loadIterator());
170 il.append(methodGen.loadHandler());
171 final int method = cpg.addMethodref(classGen.getClassName(),
172 methodName, ATTR_SET_SIG);
173 il.append(new INVOKESPECIAL(method));
174 }
175
176 // Translate other used attribute sets first, as local attributes
177 // take precedence (last attributes overrides first)
178 if (_useSets != null) _useSets.translate(classGen, methodGen);
179
180 // Translate all local attributes
181 final Enumeration attributes = elements();
182 while (attributes.hasMoreElements()) {
183 SyntaxTreeNode element = (SyntaxTreeNode)attributes.nextElement();
184 if (element instanceof XslAttribute) {
185 final XslAttribute attribute = (XslAttribute)element;
186 attribute.translate(classGen, methodGen);
187 }
188 }
189 final InstructionList il = methodGen.getInstructionList();
190 il.append(RETURN);
191
192 classGen.addMethod(methodGen);
193 }
194
195 public String toString() {
196 StringBuffer buf = new StringBuffer("attribute-set: ");
197 // Translate all local attributes
198 final Enumeration attributes = elements();
199 while (attributes.hasMoreElements()) {
200 final XslAttribute attribute =
201 (XslAttribute)attributes.nextElement();
202 buf.append(attribute);
203 }
204 return(buf.toString());
205 }
206 }