/* * 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: XSLTAttributeDef.java 468640 2006-10-28 06:53:53Z minchau $ */ package org.apache.xalan.processor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.StringTokenizer; import java.util.Vector; import javax.xml.transform.TransformerException; import org.apache.xalan.res.XSLMessages; import org.apache.xalan.res.XSLTErrorResources; import org.apache.xalan.templates.AVT; import org.apache.xalan.templates.Constants; import org.apache.xalan.templates.ElemTemplateElement; import org.apache.xml.utils.QName; import org.apache.xml.utils.StringToIntTable; import org.apache.xml.utils.StringVector; import org.apache.xml.utils.XML11Char; import org.apache.xpath.XPath; /** * This class defines an attribute for an element in a XSLT stylesheet, * is meant to reflect the structure defined in http://www.w3.org/TR/xslt#dtd, and the * mapping between Xalan classes and the markup attributes in the element. */ public class XSLTAttributeDef { // How to handle invalid values for this attribute static final int FATAL = 0; static final int ERROR = 1; static final int WARNING = 2; /** * Construct an instance of XSLTAttributeDef. * * @param namespace The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param type One of T_CDATA, T_URL, T_AVT, T_PATTERN, T_EXPR, T_CHAR, * T_NUMBER, T_YESNO, T_QNAME, T_QNAMES, T_ENUM, T_SIMPLEPATTERNLIST, * T_NMTOKEN, T_STRINGLIST, T_PREFIX_URLLIST, T_ENUM_OR_PQNAME, T_NCNAME. * @param required true if this is attribute is required by the XSLT specification. * @param supportsAVT true if this attribute supports AVT's. * @param errorType the type of error to issue if validation fails. One of FATAL, ERROR, WARNING. */ XSLTAttributeDef(String namespace, String name, int type, boolean required, boolean supportsAVT, int errorType) { this.m_namespace = namespace; this.m_name = name; this.m_type = type; this.m_required = required; this.m_supportsAVT = supportsAVT; this.m_errorType = errorType; } /** * Construct an instance of XSLTAttributeDef. * * @param namespace The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param type One of T_CDATA, T_URL, T_AVT, T_PATTERN, T_EXPR, * T_CHAR, T_NUMBER, T_YESNO, T_QNAME, T_QNAMES, T_ENUM, * T_SIMPLEPATTERNLIST, T_NMTOKEN, T_STRINGLIST, T_PREFIX_URLLIST, * T_ENUM_OR_PQNAME, T_NCNAME. * @param supportsAVT true if this attribute supports AVT's. * @param errorType the type of error to issue if validation fails. One of FATAL, ERROR, WARNING. * @param defaultVal The default value for this attribute. */ XSLTAttributeDef(String namespace, String name, int type, boolean supportsAVT, int errorType, String defaultVal) { this.m_namespace = namespace; this.m_name = name; this.m_type = type; this.m_required = false; this.m_supportsAVT = supportsAVT; this.m_errorType = errorType; this.m_default = defaultVal; } /** * Construct an instance of XSLTAttributeDef that uses two * enumerated values. * * @param namespace The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param required true if this attribute is required by the XSLT specification. * @param supportsAVT true if this attribute supports AVT's. * @param prefixedQNameValAllowed If true, the type is T_ENUM_OR_PQNAME * @param errorType the type of error to issue if validation fails. One of FATAL, ERROR, WARNING. * @param k1 The XSLT name of the enumerated value. * @param v1 An integer representation of k1. * @param k2 The XSLT name of the enumerated value. * @param v2 An integer representation of k2. */ XSLTAttributeDef(String namespace, String name, boolean required, boolean supportsAVT, boolean prefixedQNameValAllowed, int errorType, String k1, int v1, String k2, int v2) { this.m_namespace = namespace; this.m_name = name; this.m_type = prefixedQNameValAllowed ? this.T_ENUM_OR_PQNAME : this.T_ENUM; this.m_required = required; this.m_supportsAVT = supportsAVT; this.m_errorType = errorType; m_enums = new StringToIntTable(2); m_enums.put(k1, v1); m_enums.put(k2, v2); } /** * Construct an instance of XSLTAttributeDef that uses three * enumerated values. * * @param namespace The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param required true if this attribute is required by the XSLT specification. * @param supportsAVT true if this attribute supports AVT's. * @param prefixedQNameValAllowed If true, the type is T_ENUM_OR_PQNAME * @param errorType the type of error to issue if validation fails. One of FATAL, ERROR, WARNING. * * @param k1 The XSLT name of the enumerated value. * @param v1 An integer representation of k1. * @param k2 The XSLT name of the enumerated value. * @param v2 An integer representation of k2. * @param k3 The XSLT name of the enumerated value. * @param v3 An integer representation of k3. */ XSLTAttributeDef(String namespace, String name, boolean required, boolean supportsAVT, boolean prefixedQNameValAllowed, int errorType, String k1, int v1, String k2, int v2, String k3, int v3) { this.m_namespace = namespace; this.m_name = name; this.m_type = prefixedQNameValAllowed ? this.T_ENUM_OR_PQNAME : this.T_ENUM; this.m_required = required; this.m_supportsAVT = supportsAVT; this.m_errorType = errorType; m_enums = new StringToIntTable(3); m_enums.put(k1, v1); m_enums.put(k2, v2); m_enums.put(k3, v3); } /** * Construct an instance of XSLTAttributeDef that uses three * enumerated values. * * @param namespace The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param required true if this attribute is required by the XSLT specification. * @param supportsAVT true if this attribute supports AVT's. * @param prefixedQNameValAllowed If true, the type is T_ENUM_OR_PQNAME * @param errorType the type of error to issue if validation fails. One of FATAL, ERROR, WARNING. * @param k1 The XSLT name of the enumerated value. * @param v1 An integer representation of k1. * @param k2 The XSLT name of the enumerated value. * @param v2 An integer representation of k2. * @param k3 The XSLT name of the enumerated value. * @param v3 An integer representation of k3. * @param k4 The XSLT name of the enumerated value. * @param v4 An integer representation of k4. */ XSLTAttributeDef(String namespace, String name, boolean required, boolean supportsAVT, boolean prefixedQNameValAllowed, int errorType, String k1, int v1, String k2, int v2, String k3, int v3, String k4, int v4) { this.m_namespace = namespace; this.m_name = name; this.m_type = prefixedQNameValAllowed ? this.T_ENUM_OR_PQNAME : this.T_ENUM; this.m_required = required; this.m_supportsAVT = supportsAVT; this.m_errorType = errorType; m_enums = new StringToIntTable(4); m_enums.put(k1, v1); m_enums.put(k2, v2); m_enums.put(k3, v3); m_enums.put(k4, v4); } /** Type values that represent XSLT attribute types. */ static final int T_CDATA = 1, // <!-- Used for the type of an attribute value that is a URI reference.--> T_URL = 2, // <!-- Used for the type of an attribute value that is an // attribute value template.--> T_AVT = 3, // Attribute Value Template // <!-- Used for the type of an attribute value that is a pattern.--> T_PATTERN = 4, // <!-- Used for the type of an attribute value that is an expression.--> T_EXPR = 5, // <!-- Used for the type of an attribute value that consists // of a single character.--> T_CHAR = 6, // <!-- Used for the type of an attribute value that is a number. --> T_NUMBER = 7, // Used for boolean values T_YESNO = 8, // <!-- Used for the type of an attribute value that is a QName; the prefix // gets expanded by the XSLT processor. --> T_QNAME = 9, // <!--Used for a whitespace-separated list of QNames where the non-prefixed // entries are not to be placed in the default namespace. --> T_QNAMES = 10, // <!-- Used for enumerated values --> T_ENUM = 11, // Used for simple match patterns, i.e. xsl:strip-space spec. T_SIMPLEPATTERNLIST = 12, // Used for a known token. T_NMTOKEN = 13, // Used for a list of white-space delimited strings. T_STRINGLIST = 14, // Used for a list of white-space delimited strings. // Prefixes are checked to make sure they refer to // valid namespaces, and are resolved when processed T_PREFIX_URLLIST = 15, // Used for enumerated values, one of which could be a qname-but-not-ncname T_ENUM_OR_PQNAME = 16, // Used for the type of an attribute value that is a NCName T_NCNAME = 17, // Used for QName attributes that are always AVT. Prefix isn't resolved. T_AVT_QNAME = 18, // Used for a list of QNames where non-prefixed items are to be resolved // using the default namespace (This is only true for cdata-section-elements) T_QNAMES_RESOLVE_NULL = 19, // Used for a list of white-space delimited strings. // strings are checked to make sure they are valid // prefixes, and are not expanded when processed. T_PREFIXLIST = 20; /** Representation for an attribute in a foreign namespace. */ static final XSLTAttributeDef m_foreignAttr = new XSLTAttributeDef("*", "*", XSLTAttributeDef.T_CDATA,false, false, WARNING); /** Method name that objects may implement if they wish to have forein attributes set. */ static final String S_FOREIGNATTR_SETTER = "setForeignAttr"; /** * The allowed namespace for this element. */ private String m_namespace; /** * Get the allowed namespace for this attribute. * * @return The allowed namespace for this attribute, which may be null, or may be "*". */ String getNamespace() { return m_namespace; } /** * The name of this element. */ private String m_name; /** * Get the name of this attribute. * * @return non-null reference to the name of this attribute, which may be "*". */ String getName() { return m_name; } /** * The type of this attribute value. */ private int m_type; /** * Get the type of this attribute value. * * @return One of T_CDATA, T_URL, T_AVT, T_PATTERN, T_EXPR, T_CHAR, * T_NUMBER, T_YESNO, T_QNAME, T_QNAMES, T_ENUM, T_SIMPLEPATTERNLIST, * T_NMTOKEN, T_STRINGLIST, T_PREFIX_URLLIST, T_ENUM_OR_PQNAME. */ int getType() { return m_type; } /** * If this element is of type T_ENUM, this will contain * a map from the attribute string to the Xalan integer * value. */ private StringToIntTable m_enums; /** * If this element is of type T_ENUM, this will return * a map from the attribute string to the Xalan integer * value. * @param key The XSLT attribute value. * * @return The integer representation of the enumerated value for this attribute. * @throws Throws NullPointerException if m_enums is null. */ private int getEnum(String key) { return m_enums.get(key); } /** * If this element is of type T_ENUM, this will return * an array of strings - the values in the enumeration * * @return An array of the enumerated values permitted for this attribute. * * @throws Throws NullPointerException if m_enums is null. */ private String[] getEnumNames() { return m_enums.keys(); } /** * The default value for this attribute. */ private String m_default; /** * Get the default value for this attribute. * * @return The default value for this attribute, or null. */ String getDefault() { return m_default; } /** * Set the default value for this attribute. * * @param def String representation of the default value for this attribute. */ void setDefault(String def) { m_default = def; } /** * If true, this is a required attribute. */ private boolean m_required; /** * Get whether or not this is a required attribute. * * @return true if this is a required attribute. */ boolean getRequired() { return m_required; } /** * If true, this is attribute supports AVT's. */ private boolean m_supportsAVT; /** * Get whether or not this attribute supports AVT's. * * @return true if this attribute supports AVT's. */ boolean getSupportsAVT() { return m_supportsAVT; } int m_errorType = this.WARNING; /** * Get the type of error message to use if the attribute value is invalid. * * @return one of XSLAttributeDef.FATAL, XSLAttributeDef.ERROR, XSLAttributeDef.WARNING */ int getErrorType() { return m_errorType; } /** * String that should represent the setter method which which * may be used on objects to set a value that represents this attribute */ String m_setterString = null; /** * Return a string that should represent the setter method. * The setter method name will be created algorithmically the * first time this method is accessed, and then cached for return * by subsequent invocations of this method. * * @return String that should represent the setter method which which * may be used on objects to set a value that represents this attribute, * of null if no setter method should be called. */ public String getSetterMethodName() { if (null == m_setterString) { if (m_foreignAttr == this) { return S_FOREIGNATTR_SETTER; } else if (m_name.equals("*")) { m_setterString = "addLiteralResultAttribute"; return m_setterString; } StringBuffer outBuf = new StringBuffer(); outBuf.append("set"); if ((m_namespace != null) && m_namespace.equals(Constants.S_XMLNAMESPACEURI)) { outBuf.append("Xml"); } int n = m_name.length(); for (int i = 0; i < n; i++) { char c = m_name.charAt(i); if ('-' == c) { i++; c = m_name.charAt(i); c = Character.toUpperCase(c); } else if (0 == i) { c = Character.toUpperCase(c); } outBuf.append(c); } m_setterString = outBuf.toString(); } return m_setterString; } /** * Process an attribute string of type T_AVT into * a AVT value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value Should be an Attribute Value Template string. * * @return An AVT object that may be used to evaluate the Attribute Value Template. * * @throws org.xml.sax.SAXException which will wrap a * {@link javax.xml.transform.TransformerException}, if there is a syntax error * in the attribute value template string. */ AVT processAVT( StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { try { AVT avt = new AVT(handler, uri, name, rawName, value, owner); return avt; } catch (TransformerException te) { throw new org.xml.sax.SAXException(te); } } /** * Process an attribute string of type T_CDATA into * a String value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value non-null string reference. * * @return The value argument. * * @throws org.xml.sax.SAXException. */ Object processCDATA(StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { if (getSupportsAVT()) { try { AVT avt = new AVT(handler, uri, name, rawName, value, owner); return avt; } catch (TransformerException te) { throw new org.xml.sax.SAXException(te); } } else { return value; } } /** * Process an attribute string of type T_CHAR into * a Character value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value Should be a string with a length of 1. * * @return Character object. * * @throws org.xml.sax.SAXException if the string is not a length of 1. */ Object processCHAR( StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { if (getSupportsAVT()) { try { AVT avt = new AVT(handler, uri, name, rawName, value, owner); // If an AVT wasn't used, validate the value if ((avt.isSimple()) && (value.length() != 1)) { handleError(handler, XSLTErrorResources.INVALID_TCHAR, new Object[] {name, value},null); return null; } return avt; } catch (TransformerException te) { throw new org.xml.sax.SAXException(te); } } else { if (value.length() != 1) { handleError(handler, XSLTErrorResources.INVALID_TCHAR, new Object[] {name, value},null); return null; } return new Character(value.charAt(0)); } } /** * Process an attribute string of type T_ENUM into a int value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value non-null string that represents an enumerated value that is * valid for this element. * @param owner * * @return An Integer representation of the enumerated value if this attribute does not support * AVT. Otherwise, and AVT is returned. */ Object processENUM(StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { AVT avt = null; if (getSupportsAVT()) { try { avt = new AVT(handler, uri, name, rawName, value, owner); // If this attribute used an avt, then we can't validate at this time. if (!avt.isSimple()) return avt; } catch (TransformerException te) { throw new org.xml.sax.SAXException(te); } } int retVal = this.getEnum(value); if (retVal == StringToIntTable.INVALID_KEY) { StringBuffer enumNamesList = getListOfEnums(); handleError(handler, XSLTErrorResources.INVALID_ENUM,new Object[]{name, value, enumNamesList.toString() },null); return null; } if (getSupportsAVT()) return avt; else return new Integer(retVal); } /** * Process an attribute string of that is either an enumerated value or a qname-but-not-ncname. * Returns an AVT, if this attribute support AVT; otherwise returns int or qname. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value non-null string that represents an enumerated value that is * valid for this element. * @param owner * * @return AVT if attribute supports AVT. An Integer representation of the enumerated value if * attribute does not support AVT and an enumerated value was used. Otherwise a qname * is returned. */ Object processENUM_OR_PQNAME(StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { Object objToReturn = null; if (getSupportsAVT()) { try { AVT avt = new AVT(handler, uri, name, rawName, value, owner); if (!avt.isSimple()) return avt; else objToReturn = avt; } catch (TransformerException te) { throw new org.xml.sax.SAXException(te); } } // An avt wasn't used. int key = this.getEnum(value); if (key != StringToIntTable.INVALID_KEY) { if (objToReturn == null) objToReturn = new Integer(key); } // enum not used. Validate qname-but-not-ncname. else { try { QName qname = new QName(value, handler, true); if (objToReturn == null) objToReturn = qname; if (qname.getPrefix() == null) { StringBuffer enumNamesList = getListOfEnums(); enumNamesList.append(" <qname-but-not-ncname>"); handleError(handler,XSLTErrorResources.INVALID_ENUM,new Object[]{name, value, enumNamesList.toString() },null); return null; } } catch (IllegalArgumentException ie) { StringBuffer enumNamesList = getListOfEnums(); enumNamesList.append(" <qname-but-not-ncname>"); handleError(handler,XSLTErrorResources.INVALID_ENUM,new Object[]{name, value, enumNamesList.toString() },ie); return null; } catch (RuntimeException re) { StringBuffer enumNamesList = getListOfEnums(); enumNamesList.append(" <qname-but-not-ncname>"); handleError(handler,XSLTErrorResources.INVALID_ENUM,new Object[]{name, value, enumNamesList.toString() },re); return null; } } return objToReturn; } /** * Process an attribute string of type T_EXPR into * an XPath value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value An XSLT expression string. * * @return an XPath object that may be used for evaluation. * * @throws org.xml.sax.SAXException that wraps a * {@link javax.xml.transform.TransformerException} if the expression * string contains a syntax error. */ Object processEXPR( StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { try { XPath expr = handler.createXPath(value, owner); return expr; } catch (TransformerException te) { throw new org.xml.sax.SAXException(te); } } /** * Process an attribute string of type T_NMTOKEN into * a String value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value A NMTOKEN string. * * @return the value argument or an AVT if this attribute supports AVTs. * * @throws org.xml.sax.SAXException if the value is not a valid nmtoken */ Object processNMTOKEN(StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { if (getSupportsAVT()) { try { AVT avt = new AVT(handler, uri, name, rawName, value, owner); // If an AVT wasn't used, validate the value if ((avt.isSimple()) && (!XML11Char.isXML11ValidNmtoken(value))) { handleError(handler,XSLTErrorResources.INVALID_NMTOKEN, new Object[] {name,value},null); return null; } return avt; } catch (TransformerException te) { throw new org.xml.sax.SAXException(te); } } else { if (!XML11Char.isXML11ValidNmtoken(value)) { handleError(handler,XSLTErrorResources.INVALID_NMTOKEN, new Object[] {name,value},null); return null; } } return value; } /** * Process an attribute string of type T_PATTERN into * an XPath match pattern value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value A match pattern string. * * @return An XPath pattern that may be used to evaluate the XPath. * * @throws org.xml.sax.SAXException that wraps a * {@link javax.xml.transform.TransformerException} if the match pattern * string contains a syntax error. */ Object processPATTERN( StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { try { XPath pattern = handler.createMatchPatternXPath(value, owner); return pattern; } catch (TransformerException te) { throw new org.xml.sax.SAXException(te); } } /** * Process an attribute string of type T_NUMBER into * a double value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value A string that can be parsed into a double value. * @param number * * @return A Double object. * * @throws org.xml.sax.SAXException that wraps a * {@link javax.xml.transform.TransformerException} * if the string does not contain a parsable number. */ Object processNUMBER( StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { if (getSupportsAVT()) { Double val; AVT avt = null; try { avt = new AVT(handler, uri, name, rawName, value, owner); // If this attribute used an avt, then we can't validate at this time. if (avt.isSimple()) { val = Double.valueOf(value); } } catch (TransformerException te) { throw new org.xml.sax.SAXException(te); } catch (NumberFormatException nfe) { handleError(handler,XSLTErrorResources.INVALID_NUMBER, new Object[] {name, value}, nfe); return null; } return avt; } else { try { return Double.valueOf(value); } catch (NumberFormatException nfe) { handleError(handler,XSLTErrorResources.INVALID_NUMBER, new Object[] {name, value}, nfe); return null; } } } /** * Process an attribute string of type T_QNAME into a QName value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value A string that represents a potentially prefix qualified name. * @param owner * * @return A QName object if this attribute does not support AVT's. Otherwise, an AVT * is returned. * * @throws org.xml.sax.SAXException if the string contains a prefix that can not be * resolved, or the string contains syntax that is invalid for a qualified name. */ Object processQNAME( StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { try { QName qname = new QName(value, handler, true); return qname; } catch (IllegalArgumentException ie) { // thrown by QName constructor handleError(handler,XSLTErrorResources.INVALID_QNAME, new Object[] {name, value},ie); return null; } catch (RuntimeException re) { // thrown by QName constructor handleError(handler,XSLTErrorResources.INVALID_QNAME, new Object[] {name, value},re); return null; } } /** * Process an attribute string of type T_QNAME into a QName value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value A string that represents a potentially prefix qualified name. * @param owner * * @return An AVT is returned. * * @throws org.xml.sax.SAXException if the string contains a prefix that can not be * resolved, or the string contains syntax that is invalid for a qualified name. */ Object processAVT_QNAME( StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { AVT avt = null; try { avt = new AVT(handler, uri, name, rawName, value, owner); // If an AVT wasn't used, validate the value if (avt.isSimple()) { int indexOfNSSep = value.indexOf(':'); if (indexOfNSSep >= 0) { String prefix = value.substring(0, indexOfNSSep); if (!XML11Char.isXML11ValidNCName(prefix)) { handleError(handler,XSLTErrorResources.INVALID_QNAME,new Object[]{name,value },null); return null; } } String localName = (indexOfNSSep < 0) ? value : value.substring(indexOfNSSep + 1); if ((localName == null) || (localName.length() == 0) || (!XML11Char.isXML11ValidNCName(localName))) { handleError(handler,XSLTErrorResources.INVALID_QNAME,new Object[]{name,value },null ); return null; } } } catch (TransformerException te) { // thrown by AVT constructor throw new org.xml.sax.SAXException(te); } return avt; } /** * Process an attribute string of type NCName into a String * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value A string that represents a potentially prefix qualified name. * @param owner * * @return A String object if this attribute does not support AVT's. Otherwise, an AVT * is returned. * * @throws org.xml.sax.SAXException if the string contains a prefix that can not be * resolved, or the string contains syntax that is invalid for a NCName. */ Object processNCNAME( StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { if (getSupportsAVT()) { AVT avt = null; try { avt = new AVT(handler, uri, name, rawName, value, owner); // If an AVT wasn't used, validate the value if ((avt.isSimple()) && (!XML11Char.isXML11ValidNCName(value))) { handleError(handler,XSLTErrorResources.INVALID_NCNAME,new Object[] {name,value},null); return null; } return avt; } catch (TransformerException te) { // thrown by AVT constructor throw new org.xml.sax.SAXException(te); } } else { if (!XML11Char.isXML11ValidNCName(value)) { handleError(handler,XSLTErrorResources.INVALID_NCNAME,new Object[] {name,value},null); return null; } return value; } } /** * Process an attribute string of type T_QNAMES into a vector of QNames where * the specification requires that non-prefixed elements not be placed in a * namespace. (See section 2.4 of XSLT 1.0.) * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value A whitespace delimited list of qualified names. * * @return a Vector of QName objects. * * @throws org.xml.sax.SAXException if the one of the qualified name strings * contains a prefix that can not be * resolved, or a qualified name contains syntax that is invalid for a qualified name. */ Vector processQNAMES( StylesheetHandler handler, String uri, String name, String rawName, String value) throws org.xml.sax.SAXException { StringTokenizer tokenizer = new StringTokenizer(value, " \t\n\r\f"); int nQNames = tokenizer.countTokens(); Vector qnames = new Vector(nQNames); for (int i = 0; i < nQNames; i++) { // Fix from Alexander Rudnev qnames.addElement(new QName(tokenizer.nextToken(), handler)); } return qnames; } /** * Process an attribute string of type T_QNAMES_RESOLVE_NULL into a vector * of QNames where the specification requires non-prefixed elements to be * placed in the default namespace. (See section 16 of XSLT 1.0; the * <em>only</em> time that this will get called is for the * <code>cdata-section-elements</code> attribute on <code>xsl:output</code>. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value A whitespace delimited list of qualified names. * * @return a Vector of QName objects. * * @throws org.xml.sax.SAXException if the one of the qualified name strings * contains a prefix that can not be resolved, or a qualified name contains * syntax that is invalid for a qualified name. */ final Vector processQNAMESRNU(StylesheetHandler handler, String uri, String name, String rawName, String value) throws org.xml.sax.SAXException { StringTokenizer tokenizer = new StringTokenizer(value, " \t\n\r\f"); int nQNames = tokenizer.countTokens(); Vector qnames = new Vector(nQNames); String defaultURI = handler.getNamespaceForPrefix(""); for (int i = 0; i < nQNames; i++) { String tok = tokenizer.nextToken(); if (tok.indexOf(':') == -1) { qnames.addElement(new QName(defaultURI,tok)); } else { qnames.addElement(new QName(tok, handler)); } } return qnames; } /** * Process an attribute string of type T_SIMPLEPATTERNLIST into * a vector of XPath match patterns. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value A whitespace delimited list of simple match patterns. * * @return A Vector of XPath objects. * * @throws org.xml.sax.SAXException that wraps a * {@link javax.xml.transform.TransformerException} if one of the match pattern * strings contains a syntax error. */ Vector processSIMPLEPATTERNLIST( StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { try { StringTokenizer tokenizer = new StringTokenizer(value, " \t\n\r\f"); int nPatterns = tokenizer.countTokens(); Vector patterns = new Vector(nPatterns); for (int i = 0; i < nPatterns; i++) { XPath pattern = handler.createMatchPatternXPath(tokenizer.nextToken(), owner); patterns.addElement(pattern); } return patterns; } catch (TransformerException te) { throw new org.xml.sax.SAXException(te); } } /** * Process an attribute string of type T_STRINGLIST into * a vector of XPath match patterns. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value a whitespace delimited list of string values. * * @return A StringVector of the tokenized strings. */ StringVector processSTRINGLIST(StylesheetHandler handler, String uri, String name, String rawName, String value) { StringTokenizer tokenizer = new StringTokenizer(value, " \t\n\r\f"); int nStrings = tokenizer.countTokens(); StringVector strings = new StringVector(nStrings); for (int i = 0; i < nStrings; i++) { strings.addElement(tokenizer.nextToken()); } return strings; } /** * Process an attribute string of type T_URLLIST into * a vector of prefixes that may be resolved to URLs. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value A list of whitespace delimited prefixes. * * @return A vector of strings that may be resolved to URLs. * * @throws org.xml.sax.SAXException if one of the prefixes can not be resolved. */ StringVector processPREFIX_URLLIST( StylesheetHandler handler, String uri, String name, String rawName, String value) throws org.xml.sax.SAXException { StringTokenizer tokenizer = new StringTokenizer(value, " \t\n\r\f"); int nStrings = tokenizer.countTokens(); StringVector strings = new StringVector(nStrings); for (int i = 0; i < nStrings; i++) { String prefix = tokenizer.nextToken(); String url = handler.getNamespaceForPrefix(prefix); if (url != null) strings.addElement(url); else throw new org.xml.sax.SAXException(XSLMessages.createMessage(XSLTErrorResources.ER_CANT_RESOLVE_NSPREFIX, new Object[] {prefix})); } return strings; } /** * Process an attribute string of type T_PREFIXLIST into * a vector of prefixes that may be resolved to URLs. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value A list of whitespace delimited prefixes. * * @return A vector of strings that may be resolved to URLs. * * @throws org.xml.sax.SAXException if one of the prefixes can not be resolved. */ StringVector processPREFIX_LIST( StylesheetHandler handler, String uri, String name, String rawName, String value) throws org.xml.sax.SAXException { StringTokenizer tokenizer = new StringTokenizer(value, " \t\n\r\f"); int nStrings = tokenizer.countTokens(); StringVector strings = new StringVector(nStrings); for (int i = 0; i < nStrings; i++) { String prefix = tokenizer.nextToken(); String url = handler.getNamespaceForPrefix(prefix); if (prefix.equals(Constants.ATTRVAL_DEFAULT_PREFIX) || url != null) strings.addElement(prefix); else throw new org.xml.sax.SAXException( XSLMessages.createMessage( XSLTErrorResources.ER_CANT_RESOLVE_NSPREFIX, new Object[] {prefix})); } return strings; } /** * Process an attribute string of type T_URL into * a URL value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value non-null string that conforms to the URL syntax. * * @return The non-absolutized URL argument, in other words, the value argument. If this * attribute supports AVT, an AVT is returned. * * @throws org.xml.sax.SAXException if the URL does not conform to the URL syntax. */ Object processURL( StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { if (getSupportsAVT()) { try { AVT avt = new AVT(handler, uri, name, rawName, value, owner); // If an AVT wasn't used, validate the value // if (avt.getSimpleString() != null) { // TODO: syntax check URL value. // return SystemIDResolver.getAbsoluteURI(value, // handler.getBaseIdentifier()); //} return avt; } catch (TransformerException te) { throw new org.xml.sax.SAXException(te); } } else { // TODO: syntax check URL value. // return SystemIDResolver.getAbsoluteURI(value, // handler.getBaseIdentifier()); return value; } } /** * Process an attribute string of type T_YESNO into * a Boolean value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value A string that should be "yes" or "no". * * @return Boolean object representation of the value. * * @throws org.xml.sax.SAXException */ private Boolean processYESNO( StylesheetHandler handler, String uri, String name, String rawName, String value) throws org.xml.sax.SAXException { // Is this already checked somewhere else? -sb if (!(value.equals("yes") || value.equals("no"))) { handleError(handler, XSLTErrorResources.INVALID_BOOLEAN, new Object[] {name,value}, null); return null; } return new Boolean(value.equals("yes") ? true : false); } /** * Process an attribute value. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param uri The Namespace URI, or an empty string. * @param name The local name (without prefix), or empty string if not namespace processing. * @param rawName The qualified name (with prefix). * @param value The unprocessed string value of the attribute. * * @return The processed Object representation of the attribute. * * @throws org.xml.sax.SAXException if the attribute value can not be processed. */ Object processValue( StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner) throws org.xml.sax.SAXException { int type = getType(); Object processedValue = null; switch (type) { case T_AVT : processedValue = processAVT(handler, uri, name, rawName, value, owner); break; case T_CDATA : processedValue = processCDATA(handler, uri, name, rawName, value, owner); break; case T_CHAR : processedValue = processCHAR(handler, uri, name, rawName, value, owner); break; case T_ENUM : processedValue = processENUM(handler, uri, name, rawName, value, owner); break; case T_EXPR : processedValue = processEXPR(handler, uri, name, rawName, value, owner); break; case T_NMTOKEN : processedValue = processNMTOKEN(handler, uri, name, rawName, value, owner); break; case T_PATTERN : processedValue = processPATTERN(handler, uri, name, rawName, value, owner); break; case T_NUMBER : processedValue = processNUMBER(handler, uri, name, rawName, value, owner); break; case T_QNAME : processedValue = processQNAME(handler, uri, name, rawName, value, owner); break; case T_QNAMES : processedValue = processQNAMES(handler, uri, name, rawName, value); break; case T_QNAMES_RESOLVE_NULL: processedValue = processQNAMESRNU(handler, uri, name, rawName, value); break; case T_SIMPLEPATTERNLIST : processedValue = processSIMPLEPATTERNLIST(handler, uri, name, rawName, value, owner); break; case T_URL : processedValue = processURL(handler, uri, name, rawName, value, owner); break; case T_YESNO : processedValue = processYESNO(handler, uri, name, rawName, value); break; case T_STRINGLIST : processedValue = processSTRINGLIST(handler, uri, name, rawName, value); break; case T_PREFIX_URLLIST : processedValue = processPREFIX_URLLIST(handler, uri, name, rawName, value); break; case T_ENUM_OR_PQNAME : processedValue = processENUM_OR_PQNAME(handler, uri, name, rawName, value, owner); break; case T_NCNAME : processedValue = processNCNAME(handler, uri, name, rawName, value, owner); break; case T_AVT_QNAME : processedValue = processAVT_QNAME(handler, uri, name, rawName, value, owner); break; case T_PREFIXLIST : processedValue = processPREFIX_LIST(handler, uri, name, rawName, value); break; default : } return processedValue; } /** * Set the default value of an attribute. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param elem The object on which the property will be set. * * @throws org.xml.sax.SAXException wraps an invocation exception if the * setter method can not be invoked on the object. */ void setDefAttrValue(StylesheetHandler handler, ElemTemplateElement elem) throws org.xml.sax.SAXException { setAttrValue(handler, this.getNamespace(), this.getName(), this.getName(), this.getDefault(), elem); } /** * Get the primative type for the class, if there * is one. If the class is a Double, for instance, * this will return double.class. If the class is not one * of the 9 primative types, it will return the same * class that was passed in. * * @param obj The object which will be resolved to a primative class object if possible. * * @return The most primative class representation possible for the object, never null. */ private Class getPrimativeClass(Object obj) { if (obj instanceof XPath) return XPath.class; Class cl = obj.getClass(); if (cl == Double.class) { cl = double.class; } if (cl == Float.class) { cl = float.class; } else if (cl == Boolean.class) { cl = boolean.class; } else if (cl == Byte.class) { cl = byte.class; } else if (cl == Character.class) { cl = char.class; } else if (cl == Short.class) { cl = short.class; } else if (cl == Integer.class) { cl = int.class; } else if (cl == Long.class) { cl = long.class; } return cl; } /** * StringBuffer containing comma delimited list of valid values for ENUM type. * Used to build error message. */ private StringBuffer getListOfEnums() { StringBuffer enumNamesList = new StringBuffer(); String [] enumValues = this.getEnumNames(); for (int i = 0; i < enumValues.length; i++) { if (i > 0) { enumNamesList.append(' '); } enumNamesList.append(enumValues[i]); } return enumNamesList; } /** * Set a value on an attribute. * * @param handler non-null reference to current StylesheetHandler that is constructing the Templates. * @param attrUri The Namespace URI of the attribute, or an empty string. * @param attrLocalName The local name (without prefix), or empty string if not namespace processing. * @param attrRawName The raw name of the attribute, including possible prefix. * @param attrValue The attribute's value. * @param elem The object that should contain a property that represents the attribute. * * @throws org.xml.sax.SAXException */ boolean setAttrValue( StylesheetHandler handler, String attrUri, String attrLocalName, String attrRawName, String attrValue, ElemTemplateElement elem) throws org.xml.sax.SAXException { if(attrRawName.equals("xmlns") || attrRawName.startsWith("xmlns:")) return true; String setterString = getSetterMethodName(); // If this is null, then it is a foreign namespace and we // do not process it. if (null != setterString) { try { Method meth; Object[] args; if(setterString.equals(S_FOREIGNATTR_SETTER)) { // workaround for possible crimson bug if( attrUri==null) attrUri=""; // First try to match with the primative value. Class sclass = attrUri.getClass(); Class[] argTypes = new Class[]{ sclass, sclass, sclass, sclass }; meth = elem.getClass().getMethod(setterString, argTypes); args = new Object[]{ attrUri, attrLocalName, attrRawName, attrValue }; } else { Object value = processValue(handler, attrUri, attrLocalName, attrRawName, attrValue, elem); // If a warning was issued because the value for this attribute was // invalid, then the value will be null. Just return if (null == value) return false; // First try to match with the primative value. Class[] argTypes = new Class[]{ getPrimativeClass(value) }; try { meth = elem.getClass().getMethod(setterString, argTypes); } catch (NoSuchMethodException nsme) { Class cl = ((Object) value).getClass(); // If this doesn't work, try it with the non-primative value; argTypes[0] = cl; meth = elem.getClass().getMethod(setterString, argTypes); } args = new Object[]{ value }; } meth.invoke(elem, args); } catch (NoSuchMethodException nsme) { if (!setterString.equals(S_FOREIGNATTR_SETTER)) { handler.error(XSLTErrorResources.ER_FAILED_CALLING_METHOD, new Object[]{setterString}, nsme);//"Failed calling " + setterString + " method!", nsme); return false; } } catch (IllegalAccessException iae) { handler.error(XSLTErrorResources.ER_FAILED_CALLING_METHOD, new Object[]{setterString}, iae);//"Failed calling " + setterString + " method!", iae); return false; } catch (InvocationTargetException nsme) { handleError(handler, XSLTErrorResources.WG_ILLEGAL_ATTRIBUTE_VALUE, new Object[]{ Constants.ATTRNAME_NAME, getName()}, nsme); return false; } } return true; } private void handleError(StylesheetHandler handler, String msg, Object [] args, Exception exc) throws org.xml.sax.SAXException { switch (getErrorType()) { case (FATAL): case (ERROR): handler.error(msg, args, exc); break; case (WARNING): handler.warn(msg, args); default: break; } } }