Patch for Bugzilla bug report 24988 from Joanne Tong (joannet () ca ! ibm ! com)
reviewed by myself.

Changes required to test whether an attribute value that is required to be
a QName, NCName or whitespace-separated list of QNames actually meets that
requirement.

diff --git a/src/org/apache/xalan/xsltc/compiler/ApplyTemplates.java b/src/org/apache/xalan/xsltc/compiler/ApplyTemplates.java
index 6ccfaeb..880caf1 100644
--- a/src/org/apache/xalan/xsltc/compiler/ApplyTemplates.java
+++ b/src/org/apache/xalan/xsltc/compiler/ApplyTemplates.java
@@ -80,6 +80,7 @@
 import org.apache.xalan.xsltc.compiler.util.Type;
 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
 import org.apache.xalan.xsltc.compiler.util.Util;
+import org.apache.xml.utils.XMLChar;
 
 final class ApplyTemplates extends Instruction {
     private Expression _select;
@@ -117,6 +118,10 @@
 	}
 	
 	if (mode.length() > 0) {
+            if (!XMLChar.isValidQName(mode)) {
+                ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, mode, this);
+                parser.reportError(Constants.ERROR, err);           
+            }		
 	    _modeName = parser.getQNameIgnoreDefaultNs(mode);
 	}
 	
diff --git a/src/org/apache/xalan/xsltc/compiler/AttributeSet.java b/src/org/apache/xalan/xsltc/compiler/AttributeSet.java
index 1d35c97..0a92bc5 100644
--- a/src/org/apache/xalan/xsltc/compiler/AttributeSet.java
+++ b/src/org/apache/xalan/xsltc/compiler/AttributeSet.java
@@ -76,6 +76,8 @@
 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
 import org.apache.xalan.xsltc.compiler.util.Type;
 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
+import org.apache.xalan.xsltc.compiler.util.Util;
+import org.apache.xml.utils.XMLChar;
 
 final class AttributeSet extends TopLevelElement {
 
@@ -121,7 +123,13 @@
     public void parseContents(Parser parser) {
 	
 	// Get this attribute set's name
-	_name = parser.getQNameIgnoreDefaultNs(getAttribute("name"));
+        final String name = getAttribute("name");
+        
+        if (!XMLChar.isValidQName(name)) {
+            ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
+            parser.reportError(Constants.ERROR, err);           
+        }        
+        _name = parser.getQNameIgnoreDefaultNs(name);
 	if ((_name == null) || (_name.equals(EMPTYSTRING))) {
 	    ErrorMsg msg = new ErrorMsg(ErrorMsg.UNNAMED_ATTRIBSET_ERR, this);
 	    parser.reportError(Constants.ERROR, msg);
@@ -130,6 +138,10 @@
 	// 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);
 	}
 
diff --git a/src/org/apache/xalan/xsltc/compiler/Copy.java b/src/org/apache/xalan/xsltc/compiler/Copy.java
index c33927d..ede30ba 100644
--- a/src/org/apache/xalan/xsltc/compiler/Copy.java
+++ b/src/org/apache/xalan/xsltc/compiler/Copy.java
@@ -77,6 +77,7 @@
 import org.apache.bcel.generic.InstructionList;
 import org.apache.bcel.generic.LocalVariableGen;
 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
+import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
 import org.apache.xalan.xsltc.compiler.util.Type;
 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
@@ -88,6 +89,10 @@
     public void parseContents(Parser parser) {
 	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);
 	}
 	parseChildren(parser);
diff --git a/src/org/apache/xalan/xsltc/compiler/DecimalFormatting.java b/src/org/apache/xalan/xsltc/compiler/DecimalFormatting.java
index ac5cbf6..23f1a2e 100644
--- a/src/org/apache/xalan/xsltc/compiler/DecimalFormatting.java
+++ b/src/org/apache/xalan/xsltc/compiler/DecimalFormatting.java
@@ -76,6 +76,7 @@
 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
 import org.apache.xalan.xsltc.compiler.util.Type;
 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
+import org.apache.xml.utils.XMLChar;
 
 final class DecimalFormatting extends TopLevelElement {
 
@@ -96,10 +97,17 @@
      */
     public void parseContents(Parser parser) {
 	// Get the name of these decimal formatting symbols
-	_name = parser.getQNameIgnoreDefaultNs(getAttribute("name"));
-	if (_name == null) {
-	    _name = parser.getQNameIgnoreDefaultNs(EMPTYSTRING);
-	}
+        final String name = getAttribute("name");
+        if (name.length() > 0) {
+            if (!XMLChar.isValidQName(name)){
+                ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
+                parser.reportError(Constants.ERROR, err);           
+            }
+        }
+        _name = parser.getQNameIgnoreDefaultNs(name);
+        if (_name == null) {
+            _name = parser.getQNameIgnoreDefaultNs(EMPTYSTRING);
+        }         
 
 	// Check if a set of symbols has already been registered under this name
 	SymbolTable stable = parser.getSymbolTable();
diff --git a/src/org/apache/xalan/xsltc/compiler/Key.java b/src/org/apache/xalan/xsltc/compiler/Key.java
index ccc426d..8d86842 100644
--- a/src/org/apache/xalan/xsltc/compiler/Key.java
+++ b/src/org/apache/xalan/xsltc/compiler/Key.java
@@ -86,6 +86,7 @@
 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
 import org.apache.xalan.xsltc.compiler.util.Util;
 import org.apache.xalan.xsltc.dom.Axis;
+import org.apache.xml.utils.XMLChar;
 
 final class Key extends TopLevelElement {
 
@@ -116,7 +117,12 @@
     public void parseContents(Parser parser) {
 
 	// Get the required attributes and parser XPath expressions
-	_name = parser.getQNameIgnoreDefaultNs(getAttribute("name"));
+        final String name = getAttribute("name");
+        if (!XMLChar.isValidQName(name)){
+            ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
+            parser.reportError(Constants.ERROR, err);           
+        }
+        _name = parser.getQNameIgnoreDefaultNs(name);
 	_match = parser.parsePattern(this, "match", null);
 	_use = parser.parseExpression(this, "use", null);
 
diff --git a/src/org/apache/xalan/xsltc/compiler/LiteralElement.java b/src/org/apache/xalan/xsltc/compiler/LiteralElement.java
index c229ba6..0118b43 100644
--- a/src/org/apache/xalan/xsltc/compiler/LiteralElement.java
+++ b/src/org/apache/xalan/xsltc/compiler/LiteralElement.java
@@ -72,6 +72,7 @@
 import org.apache.bcel.generic.InstructionList;
 import org.apache.bcel.generic.PUSH;
 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
+import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
 import org.apache.xalan.xsltc.compiler.util.Type;
 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
@@ -290,6 +291,10 @@
 	    // in the vector or attributes to make sure that later local
 	    // attributes can override an attributes in the set.
 	    if (qname == parser.getUseAttributeSets()) {
+            	if (!Util.isValidQNames(val)) {
+                    ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, val, this);
+                    parser.reportError(Constants.ERROR, err);	
+               }
 		setFirstAttribute(new UseAttributeSets(val, parser));
 	    }
 	    // Handle xsl:extension-element-prefixes
diff --git a/src/org/apache/xalan/xsltc/compiler/Output.java b/src/org/apache/xalan/xsltc/compiler/Output.java
index a533639..81ed99b 100644
--- a/src/org/apache/xalan/xsltc/compiler/Output.java
+++ b/src/org/apache/xalan/xsltc/compiler/Output.java
@@ -80,6 +80,7 @@
 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
 import org.apache.xalan.xsltc.compiler.util.Util;
 import org.apache.xml.serializer.Encodings;
+import org.apache.xml.utils.XMLChar;
 
 final class Output extends TopLevelElement {
 
@@ -163,14 +164,21 @@
 	    outputProperties.setProperty(OutputKeys.VERSION, _version);
 	}
 
-	// Get the output method - "xml", "html", "text" or <qname>
+	// Get the output method - "xml", "html", "text" or <qname> (but not ncname)
 	_method = getAttribute("method");
 	if (_method.equals(Constants.EMPTYSTRING)) {
 	    _method = null;
 	}
 	if (_method != null) {
-	    _method = _method.toLowerCase();
-	    outputProperties.setProperty(OutputKeys.METHOD, _method);
+            _method = _method.toLowerCase();
+            if ((_method.equals("xml"))||
+                (_method.equals("html"))||
+                (_method.equals("text"))||
+                ((XMLChar.isValidQName(_method)&&(_method.indexOf(":") > 0)))) {
+	       outputProperties.setProperty(OutputKeys.METHOD, _method);
+            } else {
+                reportError(this, parser, ErrorMsg.INVALID_METHOD_IN_OUTPUT, _method);
+            }
 	}
 
 	// Get the output encoding - any value accepted here
@@ -241,8 +249,13 @@
 
 	    // Make sure to store names in expanded form
 	    while (tokens.hasMoreTokens()) {
+            	String qname = tokens.nextToken();
+                if (!XMLChar.isValidQName(qname)) {
+                    ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, qname, this);
+                    parser.reportError(Constants.ERROR, err);	
+                }	    	
 		expandedNames.append(
-		   parser.getQName(tokens.nextToken()).toString()).append(' ');
+        	   parser.getQName(qname).toString()).append(' ');
 	    }
 	    _cdata = expandedNames.toString();
 	    if (_cdataToMerge != null) {
diff --git a/src/org/apache/xalan/xsltc/compiler/ProcessingInstruction.java b/src/org/apache/xalan/xsltc/compiler/ProcessingInstruction.java
index bcc2d12..a3715e5 100644
--- a/src/org/apache/xalan/xsltc/compiler/ProcessingInstruction.java
+++ b/src/org/apache/xalan/xsltc/compiler/ProcessingInstruction.java
@@ -63,24 +63,44 @@
 
 package org.apache.xalan.xsltc.compiler;
 
+import org.apache.bcel.generic.ALOAD;
+import org.apache.bcel.generic.ASTORE;
 import org.apache.bcel.generic.ConstantPoolGen;
 import org.apache.bcel.generic.GETFIELD;
 import org.apache.bcel.generic.INVOKEINTERFACE;
+import org.apache.bcel.generic.INVOKESTATIC;
 import org.apache.bcel.generic.INVOKEVIRTUAL;
 import org.apache.bcel.generic.InstructionList;
+import org.apache.bcel.generic.LocalVariableGen;
 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
 import org.apache.xalan.xsltc.compiler.util.Type;
 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
+import org.apache.xalan.xsltc.compiler.util.Util;
+import org.apache.xml.utils.XMLChar;
 
 final class ProcessingInstruction extends Instruction {
 
     private AttributeValue _name; // name treated as AVT (7.1.3)
+    private boolean _isLiteral = false;  // specified name is not AVT  
     
     public void parseContents(Parser parser) {
 	final String name  = getAttribute("name");
-	_name = AttributeValue.create(this, name, parser);
+    
+        if (name.length() > 0) {
+            _isLiteral = Util.isLiteral(name);
+            if (_isLiteral) {
+                if (!XMLChar.isValidNCName(name)) {
+                    ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_NCNAME_ERR, name, this);
+                    parser.reportError(Constants.ERROR, err);           
+                }
+            }   
+            _name = AttributeValue.create(this, name, parser);
+        }
+        else
+            reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "name");
+            
 	if (name.equals("xml")) {
 	    reportError(this, parser, ErrorMsg.ILLEGAL_PI_ERR, "xml");
 	}
@@ -96,14 +116,41 @@
     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
 	final ConstantPoolGen cpg = classGen.getConstantPool();
 	final InstructionList il = methodGen.getInstructionList();
-
-	// Save the current handler base on the stack
-	il.append(methodGen.loadHandler());
-	il.append(DUP);		// first arg to "attributes" call
-	
-	// push attribute name
-	_name.translate(classGen, methodGen);// 2nd arg
-
+    
+        if (!_isLiteral) {
+            // if the ncname is an AVT, then the ncname has to be checked at runtime if it is a valid ncname
+            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 checkNCName if the name is an AVT
+            final int check = cpg.addMethodref(BASIS_LIBRARY_CLASS, "checkNCName",
+                                "("
+                                +STRING_SIG
+                                +")V");                 
+                                il.append(new INVOKESTATIC(check));
+            
+            // Save the current handler base on the stack
+            il.append(methodGen.loadHandler());
+            il.append(DUP);     // first arg to "attributes" call            
+            
+            // load name value again    
+            il.append(new ALOAD(nameValue.getIndex()));            
+        } else {    
+            // Save the current handler base on the stack
+            il.append(methodGen.loadHandler());
+            il.append(DUP);     // first arg to "attributes" call
+            
+            // Push attribute name
+            _name.translate(classGen, methodGen);// 2nd arg
+        
+        }
+        
 	il.append(classGen.loadTranslet());
 	il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
 					       "stringValueHandler",
diff --git a/src/org/apache/xalan/xsltc/compiler/Template.java b/src/org/apache/xalan/xsltc/compiler/Template.java
index 4d2856c..3512e8b 100644
--- a/src/org/apache/xalan/xsltc/compiler/Template.java
+++ b/src/org/apache/xalan/xsltc/compiler/Template.java
@@ -78,6 +78,8 @@
 import org.apache.xalan.xsltc.compiler.util.Type;
 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
 import org.apache.xalan.xsltc.compiler.util.Util;
+import org.apache.xml.utils.XMLChar;
+
 
 public final class Template extends TopLevelElement {
 
@@ -233,10 +235,18 @@
 	_stylesheet = super.getStylesheet();
 
 	if (name.length() > 0) {
+            if (!XMLChar.isValidQName(name)) {
+                ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
+                parser.reportError(Constants.ERROR, err);           
+            }                
 	    _name = parser.getQNameIgnoreDefaultNs(name);
 	}
 	
 	if (mode.length() > 0) {
+            if (!XMLChar.isValidQName(mode)) {
+                ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, mode, this);
+                parser.reportError(Constants.ERROR, err);           
+            } 		
 	    _mode = parser.getQNameIgnoreDefaultNs(mode);
 	}
 	
diff --git a/src/org/apache/xalan/xsltc/compiler/XslAttribute.java b/src/org/apache/xalan/xsltc/compiler/XslAttribute.java
index eaff68d..d1cf936 100644
--- a/src/org/apache/xalan/xsltc/compiler/XslAttribute.java
+++ b/src/org/apache/xalan/xsltc/compiler/XslAttribute.java
@@ -67,10 +67,14 @@
 
 import java.util.Vector;
 
+import org.apache.bcel.generic.ALOAD;
+import org.apache.bcel.generic.ASTORE;
 import org.apache.bcel.generic.ConstantPoolGen;
 import org.apache.bcel.generic.GETFIELD;
+import org.apache.bcel.generic.INVOKESTATIC;
 import org.apache.bcel.generic.INVOKEVIRTUAL;
 import org.apache.bcel.generic.InstructionList;
+import org.apache.bcel.generic.LocalVariableGen;
 import org.apache.bcel.generic.PUSH;
 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
@@ -78,6 +82,7 @@
 import org.apache.xalan.xsltc.compiler.util.Type;
 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
 import org.apache.xalan.xsltc.compiler.util.Util;
+import org.apache.xml.utils.XMLChar;
 
 import org.apache.xml.serializer.ElemDesc;
 import org.apache.xml.serializer.SerializationHandler;
@@ -88,6 +93,7 @@
     private AttributeValue _name; 	// name treated as AVT (7.1.3)
     private AttributeValueTemplate _namespace = null;
     private boolean _ignore = false;
+    private boolean _isLiteral = false;  // specified name is not AVT  
 
     /**
      * Returns the name of the attribute
@@ -117,10 +123,18 @@
 	QName qname = parser.getQName(name, false);
 	final String prefix = qname.getPrefix();
 
-	if ((prefix != null) && (prefix.equals(XMLNS_PREFIX))) {
+        if (((prefix != null) && (prefix.equals(XMLNS_PREFIX)))||(name.equals(XMLNS_PREFIX))) {
 	    reportError(this, parser, ErrorMsg.ILLEGAL_ATTR_NAME_ERR, name);
 	    return;
 	}
+  
+        _isLiteral = Util.isLiteral(name);
+        if (_isLiteral) {
+            if (!XMLChar.isValidQName(name)) {
+                reportError(this, parser, ErrorMsg.ILLEGAL_ATTR_NAME_ERR, name);
+                return;
+            }
+        }
 
 	// Ignore attribute if preceeded by some other type of element
 	final SyntaxTreeNode parent = getParent();
@@ -190,11 +204,6 @@
 	    }
 	}
 
-	if (name.equals(XMLNS_PREFIX)) {
-	    reportError(this, parser, ErrorMsg.ILLEGAL_ATTR_NAME_ERR, name);
-	    return;
-	}
-
 	if (parent instanceof LiteralElement) {
 	    ((LiteralElement)parent).addAttribute(this);
 	}
@@ -222,7 +231,7 @@
 	final InstructionList il = methodGen.getInstructionList();
 
 	if (_ignore) return;
-	_ignore = true;
+	_ignore = true;    
 
 	// Compile code that emits any needed namespace declaration
 	if (_namespace != null) {
@@ -232,13 +241,40 @@
 	    _namespace.translate(classGen,methodGen);
 	    il.append(methodGen.namespace());
 	}
-
-	// Save the current handler base on the stack
-	il.append(methodGen.loadHandler());
-	il.append(DUP);		// first arg to "attributes" call
-	
-	// Push attribute name
-	_name.translate(classGen, methodGen);// 2nd arg
+    
+        if (!_isLiteral) {
+            // 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, "checkAttribQName",
+                            "("
+                            +STRING_SIG
+                            +")V");                 
+            il.append(new INVOKESTATIC(check));
+            
+            // Save the current handler base on the stack
+            il.append(methodGen.loadHandler());
+            il.append(DUP);     // first arg to "attributes" call            
+            
+            // load name value again    
+            il.append(new ALOAD(nameValue.getIndex()));            
+        } else {    
+            // Save the current handler base on the stack
+            il.append(methodGen.loadHandler());
+            il.append(DUP);     // first arg to "attributes" call
+            
+            // Push attribute name
+            _name.translate(classGen, methodGen);// 2nd arg
+    
+        }
 
 	// Push attribute value - shortcut for literal strings
 	if ((elementCount() == 1) && (elementAt(0) instanceof Text)) {
@@ -282,8 +318,12 @@
 	    // call "attribute"
 	    il.append(methodGen.attribute());
 	}
+            
 	// Restore old handler base from stack
 	il.append(methodGen.storeHandler());
+    
+
+        
     }
 
 }
diff --git a/src/org/apache/xalan/xsltc/compiler/XslElement.java b/src/org/apache/xalan/xsltc/compiler/XslElement.java
index 2a1128f..5f987fd 100644
--- a/src/org/apache/xalan/xsltc/compiler/XslElement.java
+++ b/src/org/apache/xalan/xsltc/compiler/XslElement.java
@@ -64,7 +64,10 @@
 
 package org.apache.xalan.xsltc.compiler;
 
+import org.apache.bcel.generic.ALOAD;
+import org.apache.bcel.generic.ASTORE;
 import org.apache.bcel.generic.ConstantPoolGen;
+import org.apache.bcel.generic.ICONST;
 import org.apache.bcel.generic.INVOKESTATIC;
 import org.apache.bcel.generic.InstructionList;
 import org.apache.bcel.generic.LocalVariableGen;
@@ -75,6 +78,7 @@
 import org.apache.xalan.xsltc.compiler.util.Type;
 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
 import org.apache.xalan.xsltc.compiler.util.Util;
+import org.apache.xml.utils.XMLChar;
 
 final class XslElement extends Instruction {
 
@@ -101,39 +105,6 @@
 	return false;
     }
 
-    /**
-     * Checks if <param>str</param> is a literal (i.e. not an AVT) or not.
-     */
-    private boolean isLiteral(String str) {
-	final int length = str.length();
-	for (int i = 0; i < length; i++) {
-	    if (str.charAt(i) == '{' && str.charAt(i + 1) != '{') {
-		return false;
-	    }
-	}
-	return true;
-    }
-
-    /**
-     * Simple check to determine if qname is legal. If it returns false
-     * then <param>str</param> is illegal; if it returns true then 
-     * <param>str</param> may or may not be legal.
-     */
-    private boolean isLegalName(String str) {
-	if (str.indexOf(' ') > -1) {
-	    return false;
-	}
-	final int colon = str.indexOf(':');
-	if (colon == 0 || colon == str.length() - 1) {
-	    return false;
-	}
-	final char first = str.charAt(0);
-	if (!Character.isLetter(first) && first != '_') {
-	    return false;
-	}
-	return true;
-    }
-
     public void parseContents(Parser parser) {
 	final SymbolTable stable = parser.getSymbolTable();
 
@@ -152,9 +123,9 @@
 	String namespace = getAttribute("namespace");
 
 	// Optimize compilation when name is known at compile time
-	_isLiteralName = isLiteral(name);
+        _isLiteralName = Util.isLiteral(name);
 	if (_isLiteralName) {
-	    if (!isLegalName(name)) {
+            if (!XMLChar.isValidQName(name)) {
 		ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_ELEM_NAME_ERR,
 					    name, this);
 		parser.reportError(WARNING, msg);
@@ -186,7 +157,7 @@
 	    }
 	    else {
 		if (prefix == EMPTYSTRING) {
-		    if (isLiteral(namespace)) {
+        	    if (Util.isLiteral(namespace)) {
 			prefix = lookupPrefix(namespace);
 			if (prefix == null) {
 			    prefix = stable.generateNamespacePrefix();
@@ -213,6 +184,10 @@
 
 	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));
 	}
 
@@ -283,11 +258,30 @@
 	}
 
 	if (!_ignore) {
-	    // Push handler for call to endElement()
-	    il.append(methodGen.loadHandler());
-
-	    // Push name and namespace URI
-	    _name.translate(classGen, methodGen);
+       
+            // 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);
 	    }
@@ -299,14 +293,16 @@
 	    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)));                
 
-	    // Invoke BasisLibrary.startXslElement()
-	    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);
diff --git a/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages.java b/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages.java
index 65f0ca0..191fe93 100644
--- a/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages.java
+++ b/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages.java
@@ -929,8 +929,38 @@
          * stylesheet (see above).
          */
         {ErrorMsg.RUNTIME_ERROR_KEY,
-        "Translet errors:"}
+        "Translet errors:"},
+        
+        /*
+         * Note to translators:  An attribute whose value is constrained to
+         * be a "QName" or a list of "QNames" had a value that was incorrect.
+         * 'QName' is an XML syntactic term that must not be translated.  The
+         * substitution text contains the actual value of the attribute.
+         */
+        {ErrorMsg.INVALID_QNAME_ERR,
+        "An attribute whose value must be a QName or whitespace-separated list of QNames had the value ''{0}''"}, 
 
+        /*
+         * Note to translators:  An attribute whose value is required to
+         * be an "NCName".
+         * 'NCName' is an XML syntactic term that must not be translated.  The
+         * substitution text contains the actual value of the attribute.
+         */
+        {ErrorMsg.INVALID_NCNAME_ERR,
+        "An attribute whose value must be an NCName had the value ''{0}''"},
+
+        /*
+         * Note to translators:  An attribute with an incorrect value was
+         * encountered.  The permitted value is one of the literal values
+         * "xml", "html" or "text"; it is also permitted to have the form of
+         * a QName that is not also an NCName.  The terms "method",
+         * "xsl:output", "xml", "html" and "text" are keywords that must not
+         * be translated.  The term "qname-but-not-ncname" is an XML syntactic
+         * term.  The substitution text contains the actual value of the
+         * attribute.
+         */
+        {ErrorMsg.INVALID_METHOD_IN_OUTPUT,
+        "The method attribute of an <xsl:output> element had the value ''{0}''.  The value must be one of 'xml', 'html', 'text', or qname-but-not-ncname"}
     };
 
 
diff --git a/src/org/apache/xalan/xsltc/compiler/util/ErrorMsg.java b/src/org/apache/xalan/xsltc/compiler/util/ErrorMsg.java
index 286005f..1954d03 100644
--- a/src/org/apache/xalan/xsltc/compiler/util/ErrorMsg.java
+++ b/src/org/apache/xalan/xsltc/compiler/util/ErrorMsg.java
@@ -183,7 +183,10 @@
     public static final String COULD_NOT_CREATE_TRANS_FACT = "COULD_NOT_CREATE_TRANS_FACT";
     public static final String TRANSLET_NAME_JAVA_CONFLICT =
                                                  "TRANSLET_NAME_JAVA_CONFLICT";
-    
+    public static final String INVALID_QNAME_ERR = "INVALID_QNAME_ERR";
+    public static final String INVALID_NCNAME_ERR = "INVALID_NCNAME_ERR";
+    public static final String INVALID_METHOD_IN_OUTPUT = "INVALID_METHOD_IN_OUTPUT";
+                                                     
     // All error messages are localized and are stored in resource bundles.
     // This array and the following 4 strings are read from that bundle.
     private static ResourceBundle _bundle;
diff --git a/src/org/apache/xalan/xsltc/compiler/util/Util.java b/src/org/apache/xalan/xsltc/compiler/util/Util.java
index 4fbdce2..6bc28fa 100644
--- a/src/org/apache/xalan/xsltc/compiler/util/Util.java
+++ b/src/org/apache/xalan/xsltc/compiler/util/Util.java
@@ -63,8 +63,11 @@
 
 package org.apache.xalan.xsltc.compiler.util;
 
+import java.util.StringTokenizer;
+
 import org.apache.bcel.generic.Type;
 import org.apache.xalan.xsltc.compiler.Constants;
+import org.apache.xml.utils.XMLChar;
 
 public final class Util {
     static public char filesep;
@@ -203,6 +206,35 @@
 	final int index = qname.lastIndexOf(":");
 	return (index > 0) ? qname.substring(0, index) : 
 	    Constants.EMPTYSTRING;
+    } 
+          
+    /**
+     * Checks if the string is a literal (i.e. not an AVT) or not.
+     */
+    public static boolean isLiteral(String str) {
+        final int length = str.length();
+        for (int i = 0; i < length - 1; i++) {
+            if (str.charAt(i) == '{' && str.charAt(i + 1) != '{') {
+        	return false;
+            }
+        }
+        return true;
     }
+    
+    /**
+     * Checks if the string is valid list of qnames
+     */
+    public static boolean isValidQNames(String str) {
+        if ((str != null) && (!str.equals(Constants.EMPTYSTRING))) {
+            final StringTokenizer tokens = new StringTokenizer(str);
+            while (tokens.hasMoreTokens()) {
+                if (!XMLChar.isValidQName(tokens.nextToken())) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }    
+      	   
 }
 
diff --git a/src/org/apache/xalan/xsltc/runtime/BasisLibrary.java b/src/org/apache/xalan/xsltc/runtime/BasisLibrary.java
index 41d1cc2..f7a01d6 100644
--- a/src/org/apache/xalan/xsltc/runtime/BasisLibrary.java
+++ b/src/org/apache/xalan/xsltc/runtime/BasisLibrary.java
@@ -93,7 +93,9 @@
 import org.w3c.dom.Document;
 import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
+import org.apache.xml.serializer.NamespaceMappings;
 import org.apache.xml.serializer.SerializationHandler;
+import org.apache.xml.utils.XMLChar;
 
 /**
  * Standard XSLT functions. All standard functions expect the current node 
@@ -1282,49 +1284,112 @@
 	    runTimeError(RUN_TIME_COPY_ERR);
 	}
     }
+    
+    /**
+     * Utility function to check if xsl:attribute has a valid qname
+     * This method should only be invoked if the name attribute is an AVT
+     */    
+    public static void checkAttribQName(String name) {
+        final int firstOccur = name.indexOf(":");
+        final int lastOccur = name.lastIndexOf(":");
+        final String localName = name.substring(lastOccur + 1);
+        
+        if (firstOccur > 0) {
+            final String newPrefix = name.substring(0, firstOccur); 
+        
+            if (firstOccur != lastOccur) {
+               final String oriPrefix = name.substring(firstOccur+1, lastOccur); 
+                if (!XMLChar.isValidNCName(oriPrefix)) {
+                    // even though the orignal prefix is ignored, it should still get checked for valid NCName
+                    runTimeError(INVALID_QNAME_ERR,oriPrefix+":"+localName);
+                }
+            }
+            
+            // prefix must be a valid NCName
+            if (!XMLChar.isValidNCName(newPrefix)) {
+                runTimeError(INVALID_QNAME_ERR,newPrefix+":"+localName); 
+            }  
+        }
+                
+        // local name must be a valid NCName and must not be XMLNS
+        if ((!XMLChar.isValidNCName(localName))||(localName.equals(Constants.XMLNS_PREFIX))) {
+            runTimeError(INVALID_QNAME_ERR,localName); 
+        }
+    }
+    
+    /**
+     * Utility function to check if a name is a valid ncname
+     * This method should only be invoked if the attribute value is an AVT
+     */    
+    public static void checkNCName(String name) {
+        if (!XMLChar.isValidNCName(name)) {
+            runTimeError(INVALID_NCNAME_ERR,name); 
+        }  
+    }        
 
     /**
+     * Utility function to check if a name is a valid qname
+     * This method should only be invoked if the attribute value is an AVT
+     */    
+    public static void checkQName(String name) {
+        if (!XMLChar.isValidQName(name)) {
+            runTimeError(INVALID_QNAME_ERR,name); 
+        }  
+    }
+    
+    /**
      * Utility function for the implementation of xsl:element.
      */
     public static String startXslElement(String qname, String namespace,
 	SerializationHandler handler, DOM dom, int node)
     {
-	try {
-	    // Get prefix from qname
-	    String prefix;
-	    final int index = qname.indexOf(':');
-
-	    if (index > 0) {
-		prefix = qname.substring(0, index);
-
-		// Handle case when prefix is not known at compile time
-		if (namespace == null || namespace.length() == 0) {
-		    namespace = dom.lookupNamespace(node, prefix);
-		}
-
-		handler.startElement(namespace, qname.substring(index+1),
-                                     qname);
-		handler.namespaceAfterStartElement(prefix, namespace); 
-	    }
-	    else {
-		// Need to generate a prefix?
-		if (namespace != null && namespace.length() > 0) {
-		    prefix = generatePrefix();
-		    qname = prefix + ':' + qname;   
-		    handler.startElement(namespace, qname, qname);   
-		    handler.namespaceAfterStartElement(prefix, namespace);
-		}
-		else {
-		    handler.startElement(null, null, qname);   
-		}
-	    }
-	}
-	catch (SAXException e) {
-	    throw new RuntimeException(e.getMessage());
-	}
-
-	return qname;
-    }
+        try {
+            // Get prefix from qname
+            String prefix;
+            final int index = qname.indexOf(':');
+            
+            if (index > 0) {
+                prefix = qname.substring(0, index);
+                
+                // Handle case when prefix is not known at compile time
+                if (namespace == null || namespace.length() == 0) {
+                    try {
+                        // not sure if this line of code ever works
+                        namespace = dom.lookupNamespace(node, prefix);
+                    }
+                    catch(RuntimeException e) {
+                        handler.flushPending();  // need to flush or else can't get namespacemappings
+                        NamespaceMappings nm = handler.getNamespaceMappings();
+                        namespace = nm.lookupNamespace(prefix);
+                        if (namespace == null) {
+                            runTimeError(NAMESPACE_PREFIX_ERR,prefix);
+                        }
+                    }
+                }
+                
+                handler.startElement(namespace, qname.substring(index+1),
+                                         qname);
+                handler.namespaceAfterStartElement(prefix, namespace); 
+            }
+            else {                      
+                // Need to generate a prefix?
+                if (namespace != null && namespace.length() > 0) {
+                    prefix = generatePrefix();
+                    qname = prefix + ':' + qname;   
+                    handler.startElement(namespace, qname, qname);   
+                    handler.namespaceAfterStartElement(prefix, namespace);
+                }
+                else {
+                    handler.startElement(null, null, qname);   
+                }
+            }
+        }
+        catch (SAXException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    
+        return qname;
+    }    
 
     /**
      * This function is used in the execution of xsl:element
@@ -1382,6 +1447,8 @@
                                            "UNSUPPORTED_EXT_ERR";
     public static final String UNKNOWN_TRANSLET_VERSION_ERR =
                                            "UNKNOWN_TRANSLET_VERSION_ERR";
+    public static final String INVALID_QNAME_ERR = "INVALID_QNAME_ERR";                                           
+    public static final String INVALID_NCNAME_ERR = "INVALID_NCNAME_ERR";
 
     // All error messages are localized and are stored in resource bundles.
     protected static ResourceBundle m_bundle;
diff --git a/src/org/apache/xalan/xsltc/runtime/ErrorMessages.java b/src/org/apache/xalan/xsltc/runtime/ErrorMessages.java
index 57b9818..2732743 100644
--- a/src/org/apache/xalan/xsltc/runtime/ErrorMessages.java
+++ b/src/org/apache/xalan/xsltc/runtime/ErrorMessages.java
@@ -278,14 +278,33 @@
         "Unrecognized XSLTC extension ''{0}''"},
 
 
-        //
-        // Note to translators:  This error message is produced if the translet
-        // class was compiled using a newer version of XSLTC and deployed for
-        // execution with an older version of XSLTC.  The substitution text is
-        // the name of the translet class.
-        //
+        /*
+         * Note to translators:  This error message is produced if the translet
+         * class was compiled using a newer version of XSLTC and deployed for
+         * execution with an older version of XSLTC.  The substitution text is
+         * the name of the translet class.
+         */
         {BasisLibrary.UNKNOWN_TRANSLET_VERSION_ERR,
-        "The specified translet, ''{0}'', was created using a version of XSLTC more recent than the version of the XSLTC run-time that is in use.  You must recompile the stylesheet or use a more recent version of XSLTC to run this translet."}
+        "The specified translet, ''{0}'', was created using a version of XSLTC more recent than the version of the XSLTC run-time that is in use.  You must recompile the stylesheet or use a more recent version of XSLTC to run this translet."},
+
+        /*
+         * Note to translators:  An attribute whose effective value is required
+         * to be a "QName" had a value that was incorrect.
+         * 'QName' is an XML syntactic term that must not be translated.  The
+         * substitution text contains the actual value of the attribute.
+         */
+        {BasisLibrary.INVALID_QNAME_ERR,
+        "An attribute whose value must be a QName had the value ''{0}''"},
+
+
+        /*
+         * Note to translators:  An attribute whose effective value is required
+         * to be a "NCName" had a value that was incorrect.
+         * 'NCName' is an XML syntactic term that must not be translated.  The
+         * substitution text contains the actual value of the attribute.
+         */
+        {BasisLibrary.INVALID_NCNAME_ERR,
+        "An attribute whose value must be an NCName had the value ''{0}''"},
     };
 
     public Object[][] getContents() {
diff --git a/src/org/apache/xml/utils/XMLChar.java b/src/org/apache/xml/utils/XMLChar.java
index cf3a1c2..bda89de 100644
--- a/src/org/apache/xml/utils/XMLChar.java
+++ b/src/org/apache/xml/utils/XMLChar.java
@@ -677,5 +677,28 @@
         }
         return false;
     } // isValidIANAEncoding(String):boolean
+    
+   /**
+     * Simple check to determine if qname is legal. If it returns false
+     * then <param>str</param> is illegal; if it returns true then 
+     * <param>str</param> is legal.
+     */
+    public static boolean isValidQName(String str) {
+       
+       final int colon = str.indexOf(':');
+       
+       if (colon == 0 || colon == str.length() - 1) {
+           return false;
+       }       
+       
+       if (colon > 0) {
+           final String prefix = str.substring(0,colon);
+           final String localPart = str.substring(colon+1);
+           return isValidNCName(prefix) && isValidNCName(localPart);
+       }
+       else {
+           return isValidNCName(str);
+       }       
+    }      
 
 } // class XMLChar