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 }