/*
 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
 */
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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: AttributeSet.java,v 1.5 2005/09/28 13:48:04 pvedula Exp $
 */

package com.sun.org.apache.xalan.internal.xsltc.compiler;

import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
import com.sun.org.apache.bcel.internal.generic.InstructionList;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.AttributeSetMethodGenerator;
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.XML11Char;
import java.util.Iterator;
import java.util.List;


Author:Jacek Ambroziak, Santiago Pericas-Geertsen, Morten Jorgensen
@LastModified: Nov 2017
/** * @author Jacek Ambroziak * @author Santiago Pericas-Geertsen * @author Morten Jorgensen * @LastModified: Nov 2017 */
final class AttributeSet extends TopLevelElement { // This prefix is used for the method name of attribute set methods private static final String AttributeSetPrefix = "$as$"; // Element contents private QName _name; private UseAttributeSets _useSets; private AttributeSet _mergeSet; private String _method; private boolean _ignore = false;
Returns the QName of this attribute set
/** * Returns the QName of this attribute set */
public QName getName() { return _name; }
Returns the method name of this attribute set. This method name is generated by the compiler (XSLTC)
/** * Returns the method name of this attribute set. This method name is * generated by the compiler (XSLTC) */
public String getMethodName() { return _method; }
Call this method to prevent a method for being compiled for this set. This is used in case several elements constitute a single set (with one name). The last element will merge itself with any previous set(s) with the same name and disable the other set(s).
/** * Call this method to prevent a method for being compiled for this set. * This is used in case several <xsl:attribute-set...> elements constitute * a single set (with one name). The last element will merge itself with * any previous set(s) with the same name and disable the other set(s). */
public void ignore() { _ignore = true; }
Parse the contents of this attribute set. Recognised attributes are "name" (required) and "use-attribute-sets" (optional).
/** * Parse the contents of this attribute set. Recognised attributes are * "name" (required) and "use-attribute-sets" (optional). */
public void parseContents(Parser parser) { // Get this attribute set's name final String name = getAttribute("name"); if (!XML11Char.isXML11ValidQName(name)) { ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this); parser.reportError(Constants.ERROR, err); } _name = parser.getQNameIgnoreDefaultNs(name); if ((_name == null) || (_name.getStringRep().equals(EMPTYSTRING))) { ErrorMsg msg = new ErrorMsg(ErrorMsg.UNNAMED_ATTRIBSET_ERR, this); parser.reportError(Constants.ERROR, msg); } // Get any included attribute sets (similar to inheritance...) 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); } _useSets = new UseAttributeSets(useSets, parser); } // Parse the contents of this node. All child elements must be // <xsl:attribute> elements. Other elements cause an error. final List<SyntaxTreeNode> contents = getContents(); final int count = contents.size(); for (int i=0; i<count; i++) { SyntaxTreeNode child = contents.get(i); if (child instanceof XslAttribute) { parser.getSymbolTable().setCurrentNode(child); child.parseContents(parser); } else if (child instanceof Text) { // ignore } else { ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_CHILD_ERR, this); parser.reportError(Constants.ERROR, msg); } } // Point the symbol table back at us... parser.getSymbolTable().setCurrentNode(this); }
Type check the contents of this element
/** * Type check the contents of this element */
public Type typeCheck(SymbolTable stable) throws TypeCheckError { if (_ignore) return (Type.Void); // _mergeSet Point to any previous definition of this attribute set _mergeSet = stable.addAttributeSet(this); _method = AttributeSetPrefix + getXSLTC().nextAttributeSetSerial(); if (_useSets != null) _useSets.typeCheck(stable); typeCheckContents(stable); return Type.Void; }
Compile a method that outputs the attributes in this set
/** * Compile a method that outputs the attributes in this set */
public void translate(ClassGenerator classGen, MethodGenerator methodGen) { if (_ignore) return; // Create a new method generator for an attribute set method methodGen = new AttributeSetMethodGenerator(_method, classGen); // Generate a reference to previous attribute-set definitions with the // same name first. Those later in the stylesheet take precedence. if (_mergeSet != null) { final ConstantPoolGen cpg = classGen.getConstantPool(); final InstructionList il = methodGen.getInstructionList(); final String methodName = _mergeSet.getMethodName(); il.append(classGen.loadTranslet()); il.append(methodGen.loadDOM()); il.append(methodGen.loadIterator()); il.append(methodGen.loadHandler()); il.append(methodGen.loadCurrentNode()); final int method = cpg.addMethodref(classGen.getClassName(), methodName, ATTR_SET_SIG); il.append(new INVOKESPECIAL(method)); } // Translate other used attribute sets first, as local attributes // take precedence (last attributes overrides first) if (_useSets != null) _useSets.translate(classGen, methodGen); // Translate all local attributes final Iterator<SyntaxTreeNode> attributes = elements(); while (attributes.hasNext()) { SyntaxTreeNode element = attributes.next(); if (element instanceof XslAttribute) { final XslAttribute attribute = (XslAttribute)element; attribute.translate(classGen, methodGen); } } final InstructionList il = methodGen.getInstructionList(); il.append(RETURN); classGen.addMethod(methodGen); } public String toString() { StringBuffer buf = new StringBuffer("attribute-set: "); // Translate all local attributes final Iterator<SyntaxTreeNode> attributes = elements(); while (attributes.hasNext()) { final XslAttribute attribute = (XslAttribute)attributes.next(); buf.append(attribute); } return(buf.toString()); } }