1 /* 2 * Copyright (c) 2015, 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: AttributeSet.java,v 1.5 2005/09/28 13:48:04 pvedula Exp $ 22 */ 23 24 package com.sun.org.apache.xalan.internal.xsltc.compiler; 25 26 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 27 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; 28 import com.sun.org.apache.bcel.internal.generic.InstructionList; 29 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.AttributeSetMethodGenerator; 30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; 32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; 36 import com.sun.org.apache.xml.internal.utils.XML11Char; 37 import java.util.Iterator; 38 import java.util.List; 39 40 /** 41 * @author Jacek Ambroziak 42 * @author Santiago Pericas-Geertsen 43 * @author Morten Jorgensen 44 */ 45 final class AttributeSet extends TopLevelElement { 46 47 // This prefix is used for the method name of attribute set methods 48 private static final String AttributeSetPrefix = "$as$"; 49 50 // Element contents 51 private QName _name; 52 private UseAttributeSets _useSets; 53 private AttributeSet _mergeSet; 54 private String _method; 55 private boolean _ignore = false; 56 57 /** 58 * Returns the QName of this attribute set 59 */ getName()60 public QName getName() { 61 return _name; 62 } 63 64 /** 65 * Returns the method name of this attribute set. This method name is 66 * generated by the compiler (XSLTC) 67 */ getMethodName()68 public String getMethodName() { 69 return _method; 70 } 71 72 /** 73 * Call this method to prevent a method for being compiled for this set. 74 * This is used in case several <xsl:attribute-set...> elements constitute 75 * a single set (with one name). The last element will merge itself with 76 * any previous set(s) with the same name and disable the other set(s). 77 */ ignore()78 public void ignore() { 79 _ignore = true; 80 } 81 82 /** 83 * Parse the contents of this attribute set. Recognised attributes are 84 * "name" (required) and "use-attribute-sets" (optional). 85 */ parseContents(Parser parser)86 public void parseContents(Parser parser) { 87 88 // Get this attribute set's name 89 final String name = getAttribute("name"); 90 91 if (!XML11Char.isXML11ValidQName(name)) { 92 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this); 93 parser.reportError(Constants.ERROR, err); 94 } 95 _name = parser.getQNameIgnoreDefaultNs(name); 96 if ((_name == null) || (_name.equals(EMPTYSTRING))) { 97 ErrorMsg msg = new ErrorMsg(ErrorMsg.UNNAMED_ATTRIBSET_ERR, this); 98 parser.reportError(Constants.ERROR, msg); 99 } 100 101 // Get any included attribute sets (similar to inheritance...) 102 final String useSets = getAttribute("use-attribute-sets"); 103 if (useSets.length() > 0) { 104 if (!Util.isValidQNames(useSets)) { 105 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, useSets, this); 106 parser.reportError(Constants.ERROR, err); 107 } 108 _useSets = new UseAttributeSets(useSets, parser); 109 } 110 111 // Parse the contents of this node. All child elements must be 112 // <xsl:attribute> elements. Other elements cause an error. 113 final List<SyntaxTreeNode> contents = getContents(); 114 final int count = contents.size(); 115 for (int i=0; i<count; i++) { 116 SyntaxTreeNode child = contents.get(i); 117 if (child instanceof XslAttribute) { 118 parser.getSymbolTable().setCurrentNode(child); 119 child.parseContents(parser); 120 } 121 else if (child instanceof Text) { 122 // ignore 123 } 124 else { 125 ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_CHILD_ERR, this); 126 parser.reportError(Constants.ERROR, msg); 127 } 128 } 129 130 // Point the symbol table back at us... 131 parser.getSymbolTable().setCurrentNode(this); 132 } 133 134 /** 135 * Type check the contents of this element 136 */ typeCheck(SymbolTable stable)137 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 138 139 if (_ignore) return (Type.Void); 140 141 // _mergeSet Point to any previous definition of this attribute set 142 _mergeSet = stable.addAttributeSet(this); 143 144 _method = AttributeSetPrefix + getXSLTC().nextAttributeSetSerial(); 145 146 if (_useSets != null) _useSets.typeCheck(stable); 147 typeCheckContents(stable); 148 return Type.Void; 149 } 150 151 /** 152 * Compile a method that outputs the attributes in this set 153 */ translate(ClassGenerator classGen, MethodGenerator methodGen)154 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 155 156 if (_ignore) return; 157 158 // Create a new method generator for an attribute set method 159 methodGen = new AttributeSetMethodGenerator(_method, classGen); 160 161 // Generate a reference to previous attribute-set definitions with the 162 // same name first. Those later in the stylesheet take precedence. 163 if (_mergeSet != null) { 164 final ConstantPoolGen cpg = classGen.getConstantPool(); 165 final InstructionList il = methodGen.getInstructionList(); 166 final String methodName = _mergeSet.getMethodName(); 167 168 il.append(classGen.loadTranslet()); 169 il.append(methodGen.loadDOM()); 170 il.append(methodGen.loadIterator()); 171 il.append(methodGen.loadHandler()); 172 il.append(methodGen.loadCurrentNode()); 173 final int method = cpg.addMethodref(classGen.getClassName(), 174 methodName, ATTR_SET_SIG); 175 il.append(new INVOKESPECIAL(method)); 176 } 177 178 // Translate other used attribute sets first, as local attributes 179 // take precedence (last attributes overrides first) 180 if (_useSets != null) _useSets.translate(classGen, methodGen); 181 182 // Translate all local attributes 183 final Iterator<SyntaxTreeNode> attributes = elements(); 184 while (attributes.hasNext()) { 185 SyntaxTreeNode element = attributes.next(); 186 if (element instanceof XslAttribute) { 187 final XslAttribute attribute = (XslAttribute)element; 188 attribute.translate(classGen, methodGen); 189 } 190 } 191 final InstructionList il = methodGen.getInstructionList(); 192 il.append(RETURN); 193 194 classGen.addMethod(methodGen); 195 } 196 toString()197 public String toString() { 198 StringBuffer buf = new StringBuffer("attribute-set: "); 199 // Translate all local attributes 200 final Iterator<SyntaxTreeNode> attributes = elements(); 201 while (attributes.hasNext()) { 202 final XslAttribute attribute = 203 (XslAttribute)attributes.next(); 204 buf.append(attribute); 205 } 206 return(buf.toString()); 207 } 208 } 209