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: LiteralAttribute.java 468650 2006-10-28 07:03:30Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler; 023 024 import org.apache.bcel.generic.ConstantPoolGen; 025 import org.apache.bcel.generic.InstructionList; 026 import org.apache.bcel.generic.PUSH; 027 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 028 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 029 import org.apache.xalan.xsltc.compiler.util.Type; 030 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 031 import org.apache.xalan.xsltc.compiler.util.Util; 032 033 import org.apache.xml.serializer.ElemDesc; 034 import org.apache.xml.serializer.SerializationHandler; 035 036 /** 037 * @author Jacek Ambroziak 038 * @author Santiago Pericas-Geertsen 039 * @author Morten Jorgensen 040 */ 041 final class LiteralAttribute extends Instruction { 042 043 private final String _name; // Attribute name (incl. prefix) 044 private final AttributeValue _value; // Attribute value 045 046 /** 047 * Creates a new literal attribute (but does not insert it into the AST). 048 * @param name the attribute name (incl. prefix) as a String. 049 * @param value the attribute value. 050 * @param parser the XSLT parser (wraps XPath parser). 051 */ 052 public LiteralAttribute(String name, String value, Parser parser, 053 SyntaxTreeNode parent) 054 { 055 _name = name; 056 setParent(parent); 057 _value = AttributeValue.create(this, value, parser); 058 } 059 060 public void display(int indent) { 061 indent(indent); 062 Util.println("LiteralAttribute name=" + _name + " value=" + _value); 063 } 064 065 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 066 _value.typeCheck(stable); 067 typeCheckContents(stable); 068 return Type.Void; 069 } 070 071 protected boolean contextDependent() { 072 return _value.contextDependent(); 073 } 074 075 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 076 final ConstantPoolGen cpg = classGen.getConstantPool(); 077 final InstructionList il = methodGen.getInstructionList(); 078 079 // push handler 080 il.append(methodGen.loadHandler()); 081 // push attribute name - namespace prefix set by parent node 082 il.append(new PUSH(cpg, _name)); 083 // push attribute value 084 _value.translate(classGen, methodGen); 085 086 // Generate code that calls SerializationHandler.addUniqueAttribute() 087 // if all attributes are unique. 088 SyntaxTreeNode parent = getParent(); 089 if (parent instanceof LiteralElement 090 && ((LiteralElement)parent).allAttributesUnique()) { 091 092 int flags = 0; 093 boolean isHTMLAttrEmpty = false; 094 ElemDesc elemDesc = ((LiteralElement)parent).getElemDesc(); 095 096 // Set the HTML flags 097 if (elemDesc != null) { 098 if (elemDesc.isAttrFlagSet(_name, ElemDesc.ATTREMPTY)) { 099 flags = flags | SerializationHandler.HTML_ATTREMPTY; 100 isHTMLAttrEmpty = true; 101 } 102 else if (elemDesc.isAttrFlagSet(_name, ElemDesc.ATTRURL)) { 103 flags = flags | SerializationHandler.HTML_ATTRURL; 104 } 105 } 106 107 if (_value instanceof SimpleAttributeValue) { 108 String attrValue = ((SimpleAttributeValue)_value).toString(); 109 110 if (!hasBadChars(attrValue) && !isHTMLAttrEmpty) { 111 flags = flags | SerializationHandler.NO_BAD_CHARS; 112 } 113 } 114 115 il.append(new PUSH(cpg, flags)); 116 il.append(methodGen.uniqueAttribute()); 117 } 118 else { 119 // call attribute 120 il.append(methodGen.attribute()); 121 } 122 } 123 124 /** 125 * Return true if at least one character in the String is considered to 126 * be a "bad" character. A bad character is one whose code is: 127 * less than 32 (a space), 128 * or greater than 126, 129 * or it is one of '<', '>', '&' or '\"'. 130 * This helps the serializer to decide whether the String needs to be escaped. 131 */ 132 private boolean hasBadChars(String value) { 133 char[] chars = value.toCharArray(); 134 int size = chars.length; 135 for (int i = 0; i < size; i++) { 136 char ch = chars[i]; 137 if (ch < 32 || 126 < ch || ch == '<' || ch == '>' || ch == '&' || ch == '\"') 138 return true; 139 } 140 return false; 141 } 142 143 /** 144 * Return the name of the attribute 145 */ 146 public String getName() { 147 return _name; 148 } 149 150 /** 151 * Return the value of the attribute 152 */ 153 public AttributeValue getValue() { 154 return _value; 155 } 156 157 }