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