- /*
- * Copyright 2001-2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /*
- * $Id: XslElement.java,v 1.23 2004/02/24 03:55:48 zongaro Exp $
- */
-
- package com.sun.org.apache.xalan.internal.xsltc.compiler;
-
- import com.sun.org.apache.bcel.internal.generic.ALOAD;
- import com.sun.org.apache.bcel.internal.generic.ASTORE;
- import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
- import com.sun.org.apache.bcel.internal.generic.ICONST;
- import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
- import com.sun.org.apache.bcel.internal.generic.InstructionList;
- import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
- import com.sun.org.apache.bcel.internal.generic.PUSH;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
- import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
- import com.sun.org.apache.xml.internal.utils.XMLChar;
-
- /**
- * @author Jacek Ambroziak
- * @author Santiago Pericas-Geertsen
- * @author Morten Jorgensen
- */
- final class XslElement extends Instruction {
-
- private String _prefix;
- private boolean _ignore = false;
- private boolean _isLiteralName = true;
- private AttributeValueTemplate _name;
- private AttributeValueTemplate _namespace;
-
- /**
- * Displays the contents of the element
- */
- public void display(int indent) {
- indent(indent);
- Util.println("Element " + _name);
- displayContents(indent + IndentIncrement);
- }
-
- /**
- * This method is now deprecated. The new implemation of this class
- * never declares the default NS.
- */
- public boolean declaresDefaultNS() {
- return false;
- }
-
- public void parseContents(Parser parser) {
- final SymbolTable stable = parser.getSymbolTable();
-
- // Handle the 'name' attribute
- String name = getAttribute("name");
- if (name == EMPTYSTRING) {
- ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_ELEM_NAME_ERR,
- name, this);
- parser.reportError(WARNING, msg);
- parseChildren(parser);
- _ignore = true; // Ignore the element if the QName is invalid
- return;
- }
-
- // Get namespace attribute
- String namespace = getAttribute("namespace");
-
- // Optimize compilation when name is known at compile time
- _isLiteralName = Util.isLiteral(name);
- if (_isLiteralName) {
- if (!XMLChar.isValidQName(name)) {
- ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_ELEM_NAME_ERR,
- name, this);
- parser.reportError(WARNING, msg);
- parseChildren(parser);
- _ignore = true; // Ignore the element if the QName is invalid
- return;
- }
-
- final QName qname = parser.getQNameSafe(name);
- String prefix = qname.getPrefix();
- String local = qname.getLocalPart();
-
- if (prefix == null) {
- prefix = EMPTYSTRING;
- }
-
- if (!hasAttribute("namespace")) {
- namespace = lookupNamespace(prefix);
- if (namespace == null) {
- ErrorMsg err = new ErrorMsg(ErrorMsg.NAMESPACE_UNDEF_ERR,
- prefix, this);
- parser.reportError(WARNING, err);
- parseChildren(parser);
- _ignore = true; // Ignore the element if prefix is undeclared
- return;
- }
- _prefix = prefix;
- _namespace = new AttributeValueTemplate(namespace, parser, this);
- }
- else {
- if (prefix == EMPTYSTRING) {
- if (Util.isLiteral(namespace)) {
- prefix = lookupPrefix(namespace);
- if (prefix == null) {
- prefix = stable.generateNamespacePrefix();
- }
- }
-
- // Prepend prefix to local name
- final StringBuffer newName = new StringBuffer(prefix);
- if (prefix != EMPTYSTRING) {
- newName.append(':');
- }
- name = newName.append(local).toString();
- }
- _prefix = prefix;
- _namespace = new AttributeValueTemplate(namespace, parser, this);
- }
- }
- else {
- _namespace = (namespace == EMPTYSTRING) ? null :
- new AttributeValueTemplate(namespace, parser, this);
- }
-
- _name = new AttributeValueTemplate(name, parser, this);
-
- final String useSets = getAttribute("use-attribute-sets");
- if (useSets.length() > 0) {
- if (!Util.isValidQNames(useSets)) {
- ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, useSets, this);
- parser.reportError(Constants.ERROR, err);
- }
- setFirstElement(new UseAttributeSets(useSets, parser));
- }
-
- parseChildren(parser);
- }
-
- /**
- * Run type check on element name & contents
- */
- public Type typeCheck(SymbolTable stable) throws TypeCheckError {
- if (!_ignore) {
- _name.typeCheck(stable);
- if (_namespace != null) {
- _namespace.typeCheck(stable);
- }
- }
- typeCheckContents(stable);
- return Type.Void;
- }
-
- /**
- * This method is called when the name of the element is known at compile time.
- * In this case, there is no need to inspect the element name at runtime to
- * determine if a prefix exists, needs to be generated, etc.
- */
- public void translateLiteral(ClassGenerator classGen, MethodGenerator methodGen) {
- final ConstantPoolGen cpg = classGen.getConstantPool();
- final InstructionList il = methodGen.getInstructionList();
-
- if (!_ignore) {
- il.append(methodGen.loadHandler());
- _name.translate(classGen, methodGen);
- il.append(DUP2);
- il.append(methodGen.startElement());
-
- if (_namespace != null) {
- il.append(methodGen.loadHandler());
- il.append(new PUSH(cpg, _prefix));
- _namespace.translate(classGen,methodGen);
- il.append(methodGen.namespace());
- }
- }
-
- translateContents(classGen, methodGen);
-
- if (!_ignore) {
- il.append(methodGen.endElement());
- }
- }
-
- /**
- * At runtime the compilation of xsl:element results in code that: (i)
- * evaluates the avt for the name, (ii) checks for a prefix in the name
- * (iii) generates a new prefix and create a new qname when necessary
- * (iv) calls startElement() on the handler (v) looks up a uri in the XML
- * when the prefix is not known at compile time (vi) calls namespace()
- * on the handler (vii) evaluates the contents (viii) calls endElement().
- */
- public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
- LocalVariableGen local = null;
- final ConstantPoolGen cpg = classGen.getConstantPool();
- final InstructionList il = methodGen.getInstructionList();
-
- // Optimize translation if element name is a literal
- if (_isLiteralName) {
- translateLiteral(classGen, methodGen);
- return;
- }
-
- if (!_ignore) {
-
- // if the qname is an AVT, then the qname has to be checked at runtime if it is a valid qname
- LocalVariableGen nameValue = methodGen.addLocalVariable2("nameValue",
- Util.getJCRefType(STRING_SIG),
- il.getEnd());
-
- // store the name into a variable first so _name.translate only needs to be called once
- _name.translate(classGen, methodGen);
- il.append(new ASTORE(nameValue.getIndex()));
- il.append(new ALOAD(nameValue.getIndex()));
-
- // call checkQName if the name is an AVT
- final int check = cpg.addMethodref(BASIS_LIBRARY_CLASS, "checkQName",
- "("
- +STRING_SIG
- +")V");
- il.append(new INVOKESTATIC(check));
-
- // Push handler for call to endElement()
- il.append(methodGen.loadHandler());
-
- // load name value again
- il.append(new ALOAD(nameValue.getIndex()));
-
- if (_namespace != null) {
- _namespace.translate(classGen, methodGen);
- }
- else {
- il.append(ACONST_NULL);
- }
-
- // Push additional arguments
- il.append(methodGen.loadHandler());
- il.append(methodGen.loadDOM());
- il.append(methodGen.loadCurrentNode());
-
- // Invoke BasisLibrary.startXslElemCheckQName()
- il.append(new INVOKESTATIC(
- cpg.addMethodref(BASIS_LIBRARY_CLASS, "startXslElement",
- "(" + STRING_SIG
- + STRING_SIG
- + TRANSLET_OUTPUT_SIG
- + DOM_INTF_SIG + "I)" + STRING_SIG)));
-
-
- }
-
- translateContents(classGen, methodGen);
-
- if (!_ignore) {
- il.append(methodGen.endElement());
- }
- }
-
- /**
- * Override this method to make sure that xsl:attributes are not
- * copied to output if this xsl:element is to be ignored
- */
- public void translateContents(ClassGenerator classGen,
- MethodGenerator methodGen) {
- final int n = elementCount();
- for (int i = 0; i < n; i++) {
- final SyntaxTreeNode item =
- (SyntaxTreeNode)getContents().elementAt(i);
- if (_ignore && item instanceof XslAttribute) continue;
- item.translate(classGen, methodGen);
- }
- }
-
- }