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