You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xerces.apache.org by je...@locus.apache.org on 2000/04/04 21:56:30 UTC

cvs commit: xml-xerces/java/src/org/apache/xerces/validators/schema Schema.java SchemaImporter.java SchemaParser.java

jeffreyr    00/04/04 12:56:29

  Added:       java/src/org/apache/xerces/validators/schema Schema.java
                        SchemaImporter.java SchemaParser.java
  Log:
  Validators Factoring for Schema
  
  Revision  Changes    Path
  1.1                  xml-xerces/java/src/org/apache/xerces/validators/schema/Schema.java
  
  Index: Schema.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xerces" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 1999, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.xerces.validators.schema;
  
  import java.util.Hashtable;
  import java.util.Vector;
  import java.util.Enumeration;
  import org.apache.xerces.framework.XMLErrorReporter;
  import org.apache.xerces.validators.common.XMLValidator;
  
  
  class Schema
  {
  	//
  	// Schema Keywords
  	//
  
      public static final String		ELT_SCHEMA			= "schema";
      public static final String		ELT_SIMPLETYPE		= "simpleType";
      public static final String		ELT_COMPLEXTYPE		= "complexType";
      public static final String		ELT_ELEMENT			= "element";
      public static final String		ELT_ATTRIBUTE		= "attribute";
      public static final String		ELT_GROUP			= "group";
  	public static final String		ELT_CHOICE			= "choice";
  	public static final String		ELT_SEQUENCE		= "seq";
  	public static final String		ELT_ALL				= "all";
      public static final String		ELT_ATTRGROUP		= "attributeGroup";
      public static final String		ELT_NOTATION		= "notation";
      public static final String		ELT_ANY				= "any";
      public static final String		ELT_ANYATTRIBUTE	= "anyAttribute";
      public static final String		ELT_ANNOTATION		= "annotation";
      public static final String		ELT_DOCUMENTATION	= "documentation";
      public static final String		ELT_APPINFO			= "appinfo";
  
      public static final String		ELT_MINEXCLUSIVE	= "minExclusive";
      public static final String		ELT_MININCLUSIVE	= "minInclusive";
      public static final String		ELT_MAXEXCLUSIVE	= "maxExclusive";
      public static final String		ELT_MAXINCLUSIVE	= "maxInclusive";
      public static final String		ELT_PATTERN			= "pattern";
      public static final String		ELT_ENUMERATION		= "enumeration";
      public static final String		ELT_PRECISION		= "precision";
      public static final String		ELT_SCALE			= "scale";
      public static final String		ELT_LENGTH			= "length";
      public static final String		ELT_MINLENGTH		= "minLength";
      public static final String		ELT_MAXLENGTH		= "maxLength";
      public static final String		ELT_ENCODING		= "encoding";
      public static final String		ELT_PERIOD			= "period";
  
      public static final String		ATT_TARGETNAMESPACE	= "targetNamespace";
      public static final String		ATT_IMPORT			= "import";
      public static final String		ATT_INCLUDE			= "include";
      public static final String		ATT_NAME			= "name";
      public static final String		ATT_TYPE			= "type";
      public static final String		ATT_REF				= "ref";
      public static final String		ATT_CONTENT			= "content";
      public static final String		ATT_ABSTRACT		= "abstract";
  	public static final String		ATT_NULLABLE		= "nullable";
  	public static final String		ATT_DEFAULT			= "default";
      public static final String		ATT_FIXED			= "fixed";
      public static final String		ATT_FINAL			= "final";
      public static final String		ATT_BLOCK			= "block";
      public static final String		ATT_BASE			= "base";
      public static final String		ATT_DERIVEDBY		= "derivedBy";
      public static final String		ATT_MINOCCURS		= "minOccurs";
      public static final String		ATT_MAXOCCURS		= "maxOccurs";
      public static final String		ATT_EQUIVCLASS		= "equivClass";
      public static final String		ATT_VALUE			= "value";
  	public static final String		ATT_USE				= "use";
  	public static final String		ATT_SYSTEM			= "system";
  	public static final String		ATT_PUBLIC			= "public";
  
      public static final String		VAL_TRUE			= "true";
      public static final String		VAL_FALSE			= "false";
      public static final String		VAL_EMPTY			= "empty";
      public static final String		VAL_ELEMENTONLY		= "elementOnly";
      public static final String		VAL_TEXTONLY		= "textOnly";
      public static final String		VAL_MIXED			= "mixed";
      public static final String		VAL_EXTENSION		= "extension";
      public static final String		VAL_RESTRICTION		= "restriction";
      public static final String		VAL_REPRODUCTION	= "reproduction";
      public static final String		VAL_ENUMERATION		= "enumeration";
      public static final String		VAL_EQUIVCLASS		= "equivClass";
      public static final String		VAL_LIST			= "list";
      public static final String		VAL_POUNDALL		= "#all";
  	public static final String		VAL_INFINITY		= "*";
  
  	public static final String		VAL_OPTIONAL		= "optional";
  	public static final String		VAL_REQUIRED		= "required";
  	public static final String		VAL_DEFAULT			= "default";
  	public static final String		VAL_FIXED			= "fixed";
  	public static final String		VAL_PROHIBITED		= "prohibited";
  
  
  	//
  	// Schema Representation Data Values
  	//
  
  	static public final int			EMPTY = 0;			// content models
  	static public final int			ELEMENT_ONLY = 1;	// content models
  	static public final int			TEXT_ONLY = 2;		// content models
  	static public final int			MIXED = 3;			// content models
  
  	public static final int			EMPTY_SET = 0;		
  	public static final int			EXTENSION = 1;
  	public static final int			RESTRICTION = 2;
  	public static final int			REPRODUCTION = 4;
  	public static final int			LIST = 8;
  	public static final int			ENUMERATION = 16;
  	public static final int			EQUIVCLASS = 32;
  
  	public static final int			CHOICE = 0;			// group orders
  	public static final int			SEQUENCE = 1;		// group orders
  	public static final int			ALL = 2;			// group orders
  
  	public static final int			OPTIONAL = 0;
  	public static final int			REQUIRED = 1;
  	public static final int			DEFAULT = 2;
  	public static final int			FIXED = 3;
  	public static final int			PROHIBITED = 4;
  
  	public static final int			INFINITY = -1;		// used for maxOccurs
  
  
  	//
  	// Helpers for toString methods
  	//
  
  	private static final String[]	CONTENT_MAP = { 
  										VAL_EMPTY, 
  										VAL_ELEMENTONLY, 
  										VAL_TEXTONLY, 
  										VAL_MIXED
  									};
  
  	private static final String[]	ORDER_MAP = { 
  										ELT_CHOICE, 
  										ELT_SEQUENCE, 
  										ELT_ALL 
  									};
  
  	private static final String[]	USE_MAP = { 
  										VAL_OPTIONAL, 
  										VAL_REQUIRED, 
  										VAL_DEFAULT, 
  										VAL_FIXED, 
  										VAL_PROHIBITED 
  									};
  
  
  	private static final String[]	DERIVEDBY_MAP = {
  										null,
  										VAL_EXTENSION,		// 1
  										VAL_RESTRICTION,	// 2
  										null,
  										VAL_REPRODUCTION,	// 4
  										null, null, null,
  										VAL_LIST,			// 8
  										null, null, null, null, null, null, null,
  										VAL_ENUMERATION		// 16
  									};
  
  
  	//
  	// Schema Instance Data
  	//
  
  	private Hashtable				fDocuments = new Hashtable ();
  	private Document				fDefaultDocument = null;
  	private XMLValidator			fValidator = null;
  	private XMLErrorReporter		fErrorReporter = null;
  
  
  	//
  	// Constructor
  	//
  
  	public Schema (XMLErrorReporter errorReporter, XMLValidator validator) {
  		fErrorReporter = errorReporter;
  		fValidator = validator;
  	}
  
  
  	//
  	// Create a new Schema Document
  	//
  
  	public Document createDocument () {
  		return new Document ();
  	}
  
  
  	//
  	// Register a Schema document (associate it with a unique namespace)
  	//
  
  	public void registerDocument (String namespace, Document document)
  	{
  		if ( namespace == null ) {
  			fDefaultDocument = document;
  		} else {
  			fDocuments.put (namespace, document);
  		}
  	}
  
  
  	//
  	// Lookup a Schema document (given it's unique namespace)
  	//
  
  	public Document lookupDocument (String namespace) {
  		if ( namespace == null ) {
  			return fDefaultDocument;
  		} else {
  			return (Document)fDocuments.get (namespace);
  		}
  	}
  
  	//
  	// Debugging
  	//
  
  	public String toString () 
  	{
  		String s = "";
  
  		for ( Enumeration e = fDocuments.keys (); e.hasMoreElements();) {
  			String namespace = (String)e.nextElement ();
  			Document doc = (Document)fDocuments.get (namespace);
  			s += namespace + ":\n";
  			s += doc.toString () + "\n";
  		}
  
  		return s;
  	}
  
  
  	//****************************************************************************************
  	// Schema Interfaces
  	//
  	//****************************************************************************************
  
  
  	public interface HasSimpleType
  	{
  		public void setSimpleType (SimpleTypeDef type) throws Exception;
  		public void setSimpleType (String name, String namespace) throws Exception;
  	}
  
  
  	public interface HasType extends HasSimpleType
  	{
  		public void setType (TypeDef type) throws Exception;
  		public void setType (String name, String namespace) throws Exception;
  	}
  
  
  
  	//****************************************************************************************
  	// Schema Classes
  	//
  	//****************************************************************************************
  
  	//********************
  	//**** Schema.Ref ****
  	//********************
  
  	public abstract class Ref
  	{
  		//
  		// Getters
  		//
  
  		public abstract String				getName ();
  		public abstract String				getNamespace ();
  
  		public String getQName () {
  			String namespace = getNamespace ();
  			String qname = namespace == null? "" : namespace + ":";
  			qname += getName();
  			return qname;
  		}
  
  		//
  		// Ref Resolution
  		//
  
  		public abstract TypeDef				resolveTypeDef ();
  		public abstract GroupDef			resolveGroupDef ();
  		public abstract AttributeGroupDef	resolveAttributeGroupDef ();
  		public abstract ElementDecl			resolveElementDecl ();
  		public abstract AttributeDecl		resolveAttributeDecl ();
  		public abstract NotationDecl		resolveNotationDecl ();
  	}
  
  	//*************************
  	//**** Schema.LocalRef ****
  	//*************************
  
  	public class LocalRef extends Ref
  	{
  		private Component		fComponent;
  
  		//
  		// Constructors
  		//
  
  		public LocalRef (Component component) {
  			fComponent = component;
  		}
  
  		//
  		// Getters
  		//
  
  		public String getName () {
  			return fComponent.getName ();
  		}
  
  		public String getNamespace () {
  			return fComponent.getNamespace ();
  		}
  
  		//
  		// Ref Resolution
  		//
  
  		public TypeDef resolveTypeDef () {
  			return (TypeDef)fComponent;
  		}
  
  		public GroupDef resolveGroupDef () {
  			return (GroupDef)fComponent;
  		}
  
  		public AttributeGroupDef resolveAttributeGroupDef () {
  			return (AttributeGroupDef)fComponent;
  		}
  
  		public ElementDecl resolveElementDecl () {
  			return (ElementDecl)fComponent;
  		}
  
  		public AttributeDecl resolveAttributeDecl () {
  			return (AttributeDecl)fComponent;
  		}
  
  		public NotationDecl resolveNotationDecl () {
  			return (NotationDecl)fComponent;
  		}
  
  	}
  
  	//*************************
  	//**** Schema.NamedRef ****
  	//*************************
  
  	public class NamedRef extends Ref
  	{
  		private String			fName;
  		private String			fNamespace;
  
  		//
  		// Constructors
  		//
  
  		public NamedRef (String name, String namespace) {
  			fName = name;
  			fNamespace = namespace;
  		}
  
  		//
  		// Getters
  		//
  
  		public String getName () {
  			return fName;
  		}
  
  		public String getNamespace () {
  			return fNamespace;
  		}
  
  		//
  		// Ref Resolution
  		//
  
  		public TypeDef resolveTypeDef () {
  			Document doc = lookupDocument (fNamespace);
  			return doc.lookupTypeDef (fName);
  		}
  
  		public GroupDef resolveGroupDef () {
  			Document doc = lookupDocument (fNamespace);
  			return doc.lookupGroupDef (fName);
  		}
  
  		public AttributeGroupDef resolveAttributeGroupDef () {
  			Document doc = lookupDocument (fNamespace);
  			return doc.lookupAttributeGroupDef (fName);
  		}
  
  		public ElementDecl resolveElementDecl () {
  			Document doc = lookupDocument (fNamespace);
  			return doc.lookupElementDecl (fName);
  		}
  
  		public AttributeDecl resolveAttributeDecl () {
  			Document doc = lookupDocument (fNamespace);
  			return doc.lookupAttributeDecl (fName);
  		}
  
  		public NotationDecl resolveNotationDecl () {
  			Document doc = lookupDocument (fNamespace);
  			return doc.lookupNotationDecl (fName);
  		}
  	}
  
  	//***************************
  	//**** Schema.Annotation ****
  	//***************************
  
  	public class Annotation 
  	{
  		private Vector			fDocumentation = null;
  		private Vector			fAppInfo = null;
  
  		public void addDocumentation (String documentation) {
  			if ( fDocumentation == null ) fDocumentation = new Vector ();
  			fDocumentation.addElement (documentation);
  		}
  
  		public void addAppInfo (String appInfo) {
  			if ( fAppInfo == null ) fAppInfo = new Vector ();
  			fAppInfo.addElement (appInfo);
  		}
  
  		public String toString () {
  			String s = "<" + ELT_ANNOTATION + ">\n";
  
  			if ( fDocumentation != null ) {
  				for (int i=0; i<fDocumentation.size(); i++) {
  					String doc = (String)fDocumentation.elementAt (i);
  					s += "  <" + ELT_DOCUMENTATION + ">" + doc + "</" + ELT_DOCUMENTATION + ">\n";
  				}
  			}
  
  			if ( fAppInfo != null ) {
  				for (int i=0; i<fAppInfo.size(); i++) {
  					String appInfo = (String)fAppInfo.elementAt (i);
  					s += "  <" + ELT_APPINFO + ">" + appInfo + "</" + ELT_APPINFO + ">\n";
  				}
  			}
  
  			s += "</" + ELT_ANNOTATION + ">\n";
  
  			return s;
  		}
  	}
  
  	//**************************
  	//**** Schema.Component ****
  	//**************************
  
  	public class Component 
  	{
  		private Document	fDocument = null;
  		private String		fName = null;
  
  		public Component (Document doc) {
  			fDocument = doc;
  		}
  
  		//
  		// Setters
  		//
  
  		public void setName (String name) {
  			fName = name;
  		}
  
  		//
  		// Getters
  		//
  
  		public String getName () {
  			return fName;
  		}
  
  		public String getQName () {
  			String namespace = getNamespace ();
  			String name = getName ();
  			if ( namespace != null ) {
  				return namespace + ":" + name;
  			} else {
  				return name;
  			}
  		}
  
  		public Document getDocument () {
  			return fDocument;
  		}
  
  		public String getNamespace () {
  			return fDocument.getNamespace ();
  		}
  	}
  
  	//***********************************
  	//**** Schema.AnnotatedComponent ****
  	//***********************************
  
  	public class AnnotatedComponent extends Component
  	{
  		private Annotation		fAnnotation = null;
  
  		public AnnotatedComponent (Document doc) {
  			super (doc);
  		}
  
  		public void setAnnotation (Annotation annotation) {
  			fAnnotation = annotation;
  		}
  
  		public Annotation getAnnotation () {
  			return fAnnotation;
  		}
  
  		public String toString () {
  			return annotationToString ();
  		}
  
  		public String annotationToString () {
  			if ( fAnnotation != null ) {
  				return fAnnotation.toString ();
  			} else {
  				return "";
  			}
  		}
  	}
  
  	//*************************
  	//**** Schema.Document ****
  	//*************************
  
  	public class Document
  	{
  		// ISSUE:	Should Schemas have multiple annotations?
  		//			How is order and relationship to interspersed
  		//			components maintained?
  
  		private String			fNamespace = null;
  		private Vector			fAnnotations = new Vector ();
  		private Hashtable		fTypeDefs = new Hashtable ();
  		private Hashtable		fGroupDefs = new Hashtable ();
  		private Hashtable		fAttrGroupDefs = new Hashtable ();
  		private Hashtable		fElementDecls = new Hashtable ();
  		private Hashtable		fAttributeDecls = new Hashtable ();
  		private Hashtable		fNotationDecls = new Hashtable ();
  
  		//
  		// Getters
  		//
  
  		public String getNamespace () {
  			return fNamespace;
  		}
  
  		//
  		// Factory methods for Schema components
  		//
  
  		public Annotation createAnnotation () {
  			return new Annotation ();
  		}
  
  		public ComplexTypeDef createComplexTypeDef () {
  			return new ComplexTypeDef (this);
  		}
  
  		public SimpleTypeDef createSimpleTypeDef () {
  			return new SimpleTypeDef (this);
  		}
  
  		public Facet createFacet (String name, String value) {
  			return new Facet (name, value, this);
  		}
  
  		public GroupDef createGroupDef () {
  			return new GroupDef (this);
  		}
  
  		public AttributeGroupDef createAttributeGroupDef () {
  			return new AttributeGroupDef (this);
  		}
  
  		public ElementDecl createElementDecl () {
  			return new ElementDecl (this);
  		}
  
  		public AttributeDecl createAttributeDecl () {
  			return new AttributeDecl (this);
  		}
  
  		public NotationDecl createNotationDecl () {
  			return new NotationDecl (this);
  		}
  
  		public AttributeGroupParticle createAttributeGroupParticle () {
  			return new AttributeGroupParticle (this);
  		}
  
  		public AttributeParticle createAttributeParticle () {
  			return new AttributeParticle (this);
  		}
  
  		public GroupParticle createGroupParticle () {
  			return new GroupParticle (this);
  		}
  
  		public ElementParticle createElementParticle () {
  			return new ElementParticle (this);
  		}
  
  		//
  		// Annotations
  		//
  
  		public void addAnnotation (Annotation annotation) {
  			fAnnotations.addElement (annotation);
  		}
  
  
  		//
  		// Add Schema components to their respective symbol spaces in this
  		// Schema document.
  		//
  
  		public void registerType (String name, TypeDef typeDef) {
  			fTypeDefs.put (name, typeDef);
  		}
  
  		public void registerGroupDef (String name, GroupDef groupDef) {
  			fGroupDefs.put (name, groupDef);
  		}
  
  		public void registerAttributeGroupDef (String name, AttributeGroupDef attrGroupDef) {
  			fAttrGroupDefs.put (name, attrGroupDef);
  		}
  
  		public void registerElementDecl (String name, ElementDecl elementDecl) {
  			fElementDecls.put (name, elementDecl);
  		}
  
  		public void registerAttributeDecl (String name, AttributeDecl attributeDecl) {
  			fAttributeDecls.put (name, attributeDecl);
  		}
  
  		public void registerNotationDecl (String name, NotationDecl notationDecl) {
  			fNotationDecls.put (name, notationDecl);
  		}
  
  		//
  		// Lookup Schema Components
  		//
  
  		public TypeDef lookupTypeDef (String name) {
  			return (TypeDef)fTypeDefs.get (name);
  		}
  
  		public GroupDef lookupGroupDef (String name) {
  			return (GroupDef)fGroupDefs.get (name);
  		}
  
  		public AttributeGroupDef lookupAttributeGroupDef (String name) {
  			return (AttributeGroupDef)fAttrGroupDefs.get (name);
  		}
  
  		public ElementDecl lookupElementDecl (String name) {
  			return (ElementDecl)fElementDecls.get (name);
  		}
  
  		public AttributeDecl lookupAttributeDecl (String name) {
  			return (AttributeDecl)fAttributeDecls.get (name);
  		}
  
  		public NotationDecl lookupNotationDecl (String name) {
  			return (NotationDecl)fNotationDecls.get (name);
  		}
  
  		//
  		// Validation
  		//
  
  		public void expandEquivClassReferences () {
  			for ( Enumeration e = fElementDecls.elements (); e.hasMoreElements();) {
  				ElementDecl element = (ElementDecl)e.nextElement ();
  				ElementDecl equivClass = element.getEquivClass ();
  				if ( equivClass != null ) {
  					equivClass.addEquivElementDecl (element);
  				}
  			}
  		}
  
  		//
  		// Debugging
  		//
  
  		public String toString () 
  		{
  
  			String s = "<" + ELT_SCHEMA;
  
  			// Target Namespace
  
  			if ( fNamespace != null ) {
  				s += " " + ATT_TARGETNAMESPACE + "=" + fNamespace;
  			}
  
  			s += ">\n";
  
  
  			// Global TypeDefs
  
  			for ( Enumeration e = fTypeDefs.elements (); e.hasMoreElements();) {
  				TypeDef t = (TypeDef)e.nextElement ();
  				s += t.toString ();
  			}
  
  			// Global GroupDefs
  
  			for ( Enumeration e = fGroupDefs.elements (); e.hasMoreElements();) {
  				GroupDef g = (GroupDef)e.nextElement ();
  				s += g.toString ();
  			}
  
  			// Global AttributeGroupDefs
  
  			for ( Enumeration e = fAttrGroupDefs.elements (); e.hasMoreElements();) {
  				AttributeGroupDef ag = (AttributeGroupDef)e.nextElement ();
  				s += ag.toString ();
  			}
  
  			// Global ElementDecls
  
  			for ( Enumeration e = fElementDecls.elements (); e.hasMoreElements();) {
  				ElementDecl elem = (ElementDecl)e.nextElement ();
  				s += elem.toString ();
  			}
  
  			// Global AttributeDecls
  
  			for ( Enumeration e = fAttributeDecls.elements (); e.hasMoreElements();) {
  				AttributeDecl attr = (AttributeDecl)e.nextElement ();
  				s += attr.toString ();
  			}
  
  			// Global NotationDecls
  
  			for ( Enumeration e = fNotationDecls.elements (); e.hasMoreElements();) {
  				NotationDecl not = (NotationDecl)e.nextElement ();
  				s += not.toString ();
  			}
  			s += "</" + ELT_SCHEMA + ">\n";
  
  			return s;
  		}
  
  	}
  
  	//************************
  	//**** Schema.TypeDef ****
  	//************************
  
  	public abstract class TypeDef extends AnnotatedComponent
  	{
  		private Ref				fBaseType = null;
  		private int				fDerivedBy = 0;
  		private boolean			fIsAbstract = false;
  		private int				fFinalSet = EMPTY_SET;
  
  		//
  		// Constructor
  		//
  
  		public TypeDef (Document doc) {
  			super (doc);
  		}
  
  		//
  		// Setters
  		//
  
  		public void setBase (String name, String namespace) {
  			fBaseType = new NamedRef (name, namespace);
  		}
  
  		public void setDerivedBy (int derivedBy) {
  			fDerivedBy = derivedBy;
  		}
  
  		public void setAbstract (boolean isAbstract) {
  			fIsAbstract = isAbstract;
  		}
  
  		public void setFinal (int finalSet) {
  			fFinalSet = finalSet;
  		}
  	
  		//
  		// Getters
  		//
  
  		public TypeDef getBaseType () {
  			return fBaseType.resolveTypeDef ();
  		}
  
  		public int getDerivedBy () {
  			return fDerivedBy;
  		}
  
  		public boolean isDerivedBy (int derivedBy) {
  			return fDerivedBy == derivedBy;
  		}
  
  		public boolean isAbstract () {
  			return fIsAbstract;
  		}
  
  		public int getFinal () {
  			return fFinalSet;
  		}
  
  		public boolean canExtend () {
  			return (getFinal() & EXTENSION) == 0;
  		} 
  
  		public boolean canRestrict () {
  			return (getFinal() & RESTRICTION) == 0;
  		}
  
  		public boolean canReproduce () {
  			return (getFinal() & REPRODUCTION) == 0;
  		}
  
  		public boolean canEnumerate () {
  			return (getFinal() & ENUMERATION) == 0;
  		} 
  
  		public boolean canList () {
  			return (getFinal() & LIST) == 0;
  		} 
  
  		//
  		// Debugging
  		//
  
  		public String toString () {
  		
  			// This is an abstract base class for ComplexTypeDef and SimpleTypeDef
  			// so its string representation is just a portion of either of these.
  			// In particular, toString produces a portion of the attribute string
  			// for either.
  
  			String s = " ";
  
  			// base
  
  			if ( fBaseType != null ) {
  				s += " " + ATT_BASE + "=\'" + fBaseType.getQName() + "\'";
  			}
  
  			// derivedBy
  
  			s += " " + ATT_DERIVEDBY + "=\'" + DERIVEDBY_MAP[getDerivedBy()] + "\'";
  
  			// abstract
  			
  			s += " " + ATT_ABSTRACT + "=";
  			s += isAbstract()? "\'" + VAL_TRUE + "\'" : "\'" + VAL_FALSE + "\'";
  			
  			// final
  
  			s += " " + ATT_FINAL + "=\'";
  
  			boolean extend = canExtend ();
  			boolean restrict = canRestrict ();
  			boolean reproduce = canReproduce ();
  			boolean enumerate = canEnumerate ();
  			boolean list = canList ();
  
  			if ( (!extend && !restrict && !reproduce) || (!enumerate && !list && !restrict && !reproduce)) {
  				s += "#all";
  			} else {
  				if ( !extend ) {
  					s += " " + VAL_EXTENSION;
  				}
  				if ( !restrict ) {
  					s += " " + VAL_RESTRICTION;
  				}
  				if ( !reproduce ) {
  					s += " " + VAL_REPRODUCTION;
  				}
  				if ( !enumerate ) {
  					s += " " + VAL_ENUMERATION;
  				}
  				if ( !list ) {
  					s += " " + VAL_LIST;
  				}
  			}
  
  			s += "\'";
  
  			return s;
  		}
  	}
  
  
  	//********************
  	//**** INTERFACES ****
  	//********************
  
  	public interface AParticleHolder
  	{
  		public void add (AParticle particle);
  	}
  
  	public interface EParticleHolder
  	{
  		public void add (EParticle particle);
  	}
  
  
  	//*******************************
  	//**** Schema.ComplexTypeDef ****
  	//*******************************
  
  	public class ComplexTypeDef		extends TypeDef 
  									implements EParticleHolder, AParticleHolder
  	{
  		private int					fContent = EMPTY;
  		private int					fBlockSet = EMPTY_SET;
  		private AttributeGroupDef	fAttrGroupDef = null;
  		private GroupDef			fGroupDef = null;
  
  		//
  		// Constructor
  		//
  
  		public ComplexTypeDef (Document doc) {
  			super (doc);
  			setDerivedBy (EXTENSION);
  		}
  
  		//
  		// Setters
  		//
  
  		public void setContent (int content) {
  			fContent = content;
  		}
  		
  		public void setBlock (int blockSet) {
  			fBlockSet = blockSet;
  		}
  
  		public void add (EParticle particle) {
  			if ( fGroupDef == null ) fGroupDef = new GroupDef (getDocument());
  			fGroupDef.add (particle);
  		}
  
  		public void add (AParticle particle) {
  			if ( fAttrGroupDef == null ) fAttrGroupDef = new AttributeGroupDef (getDocument());
  			fAttrGroupDef.add (particle);
  		}
  		
  		//
  		// Getters
  		//
  
  		public int getContent () {
  			return fContent;
  		}
  
  		public boolean isContent (int content) {
  			return fContent == content;
  		}
  
  		public boolean canSubstituteExtension () {
  			return (fBlockSet & EXTENSION) == 0;
  		} 
  
  		public boolean canSubstituteRestriction () {
  			return (fBlockSet & RESTRICTION) == 0;
  		}
  
  		public boolean canSubstituteReproduction () {
  			return (fBlockSet & REPRODUCTION) == 0;
  		}
  
  		//
  		// Debugging
  		//
  
  		public String toString () {
  
  			String s = "<" + ELT_COMPLEXTYPE + " ";
  			
  			// name
  			
  			String name = getName ();
  			if ( name != null ) {
  				s += ATT_NAME + "='" + getName() + "'";
  			}
  
  			s += super.toString ();
  
  			// content
  
  			s += " " + ATT_CONTENT + "='" + CONTENT_MAP[fContent] + "'";
  
  
  			// block
  
  			s += " " + ATT_BLOCK + "='";
  
  			boolean extend = canSubstituteExtension ();
  			boolean restrict = canSubstituteRestriction ();
  			boolean reproduce = canSubstituteReproduction ();
  
  			if ( !extend && !restrict && !reproduce ) {
  				s += VAL_POUNDALL;
  			} else {
  				if ( !extend ) {
  					s += " " + VAL_EXTENSION;
  				}
  				if ( !restrict ) {
  					s += " " + VAL_RESTRICTION;
  				}
  				if ( !reproduce ) {
  					s += " " + VAL_REPRODUCTION;
  				}
  			}
  
  			s += "'>\n";
  
  			// annotation
  
  			s += annotationToString ();
  
  			// particles
  
  			if ( fGroupDef != null ) {
  				s += fGroupDef.toString ();
  			}
  
  			// attributes
  
  			if ( fAttrGroupDef != null ) {
  				s += fAttrGroupDef.toString ();
  			}
  
  			s += "</" + ELT_COMPLEXTYPE + ">\n";
  
  			return s;
  		}
  
  	}
  
  	//******************************
  	//**** Schema.SimpleTypeDef ****
  	//******************************
  
  	public class SimpleTypeDef extends TypeDef
  	{
  		private Vector			fFacets = null;
  
  		//
  		// Constructor
  		//
  
  		public SimpleTypeDef (Document doc) {
  			super (doc);
  			setDerivedBy (RESTRICTION);
  		}
  
  		//
  		// Setters
  		//
  						
  		public void addFacet (Facet facet) {
  			if ( fFacets == null ) fFacets = new Vector ();
  			fFacets.addElement (facet);
  		}
  
  		//
  		// Debugging
  		//
  
  		public String toString () {
  
  			String s = "<" + ELT_SIMPLETYPE;
  			
  			// name
  			
  			String name = getName ();
  			if ( name != null ) {
  				s += " " + ATT_NAME + "=\'" + getName() + "\'";
  			}
  
  			s += super.toString ();
  
  			s += ">\n";
  			
  			// annotations
  
  			s += annotationToString ();
  
  			// facets
  
  			if ( fFacets != null ) {
  				int numFacets = fFacets.size();
  				for (int f=0; f<numFacets; f++) {
  					Facet facet = (Facet)fFacets.elementAt (f);
  					s += facet.toString ();
  				}
  			}
  
  			s += "</" + ELT_SIMPLETYPE + ">\n";
  
  			return s;
  		}
  
  	}
  
  	//**********************
  	//**** Schema.Facet ****
  	//**********************
  
  	public class Facet extends AnnotatedComponent
  	{
  		private String	fValue = null;
  
  		public Facet (String name, String value, Document doc) {
  			super (doc);
  			setName (name);
  			fValue = value;
  		}
  
  		public String getValue () {
  			return fValue;
  		}
  
  		//
  		// Debugging
  		//
  
  		public String toString () {
  			String name = getName ();
  			String s = "<" + name + " " + ATT_VALUE + "='" + fValue + "'" + ">\n";
  			s += annotationToString ();
  			s += "</" + name + ">\n";
  			return s;
  		}
  	}
  
  	//******************************
  	//**** Schema.AttributeDecl ****
  	//******************************
  
  	public class AttributeDecl	extends		AnnotatedComponent
  								implements	HasSimpleType
  	{
  		private Ref				fTypeDef = null;
  		private int				fUse = OPTIONAL;
  		private String			fValue = null;
  
  		//
  		// Constructor
  		//
  
  		public AttributeDecl (Document doc) {
  			super (doc);
  		}
  
  		//
  		// Setters
  		//
  
  		public void setSimpleType (SimpleTypeDef typeDef) throws Exception {
  			if ( fTypeDef == null ) {
  				fTypeDef = new LocalRef (typeDef);
  			} else {
  				reportGenericSchemaError ("Type def already set");
  			}
  		}
  		
  		public void setSimpleType (String name, String namespace) throws Exception {
  			if ( fTypeDef == null ) {
  				fTypeDef = new NamedRef (name, namespace);
  			} else {
  				reportGenericSchemaError ("Type def already set");
  			}
  		}
  
  		public void setUse (int use) {
  			fUse = use;
  		}
  
  		public void setValue (String value) {
  			fValue = value;
  		}
  
  		//
  		// Getters
  		//
  
  		public SimpleTypeDef getType () {
  			return (SimpleTypeDef)fTypeDef.resolveTypeDef ();
  		}
  
  		public boolean hasTypeRef () {
  			return NamedRef.class.isInstance(fTypeDef);
  		}
  
  		public int getUse () {
  			return fUse;
  		}
  
  		public String getValue () {
  			return fValue;
  		}
  
  		public AttributeDecl createRestriction (AttributeDecl restrictions) {
  
  			// TODO: refine what is a valid restriction
  
  			AttributeDecl attrDecl = new AttributeDecl (getDocument());
  			attrDecl.setName(getName());
  			attrDecl.fTypeDef = fTypeDef;
  			attrDecl.fUse = restrictions.fUse;
  			attrDecl.fValue = (restrictions.fValue == null)? fValue : restrictions.fValue;
  			return attrDecl;
  		}
  
  		/*
  		public void collectAttributes (Hashtable attributes, boolean restrict) {
  			String name = getName ();
  			AttributeDecl attrDecl = (AttributeDecl)attributes.get (name);
  			if ( attrDecl == null ) {
  				attributes.put (name, this);
  			} else {
  				attributes.put (name, attrDecl.createRestriction(this));
  			}
  		}
  		*/
  
  
  		//
  		// Debugging
  		//
  
  		public String toString () {
  
  			String s = "<" + ELT_ATTRIBUTE;
  
  			String name = getName ();
  			if ( name != null ) {
  				s += " " + ATT_NAME + "='" + name + "'";
  			}
  
  			if ( hasTypeRef() ) {
  				s += " " + ATT_TYPE + "='" + getType().getQName() + "'";
  			}
  
  			s += " " + ATT_USE + "='" + USE_MAP[fUse] + "'";
  
  			if ( fValue != null ) {
  				s += " " + ATT_VALUE + "='" + fValue + "'";
  			}
  
  			s += ">\n";
  			
  			s += annotationToString();
  			s += getType().toString ();
  						
  			s += "</" + ELT_ATTRIBUTE + ">\n";
  			return s;
  		}
  	}
  
  	//**********************************
  	//**** Schema.AttributeGroupDef ****
  	//**********************************
  
  	public class AttributeGroupDef		extends AnnotatedComponent
  										implements AParticleHolder
  	{
  		private Vector fParticles = new Vector ();
  
  		//
  		// Constructor
  		//
  
  		public AttributeGroupDef (Document doc) {
  			super (doc);
  		}
  
  		//
  		// Setters
  		//
  
  		public void add (AParticle particle) {
  			fParticles.addElement (particle);
  		}
  
  		//
  		// Getters
  		//
  
  		/*
  		public void collectAttributes (Hashtable attributes, boolean restrict) {
  			for (int i=0; i<fParticles.size(); i++) {
  				AttributeCollector collector = (AttributeCollector)fParticles.elementAt (i);
  				collector.collectAttributes (attributes, restrict);
  			}
  		}
  		*/
  
  		//
  		// Debugging
  		//
  
  		public String toString () {
  			String s = "<" + ELT_ATTRGROUP;
  			String name = getName ();
  			if ( name != null ) {
  				s += " " + ATT_NAME + "='" + name + "'";
  			}
  			s += ">\n";
  			s += annotationToString ();
  			s += bodyToString ();
  			s += "</" + ELT_ATTRGROUP + ">\n";
  			return s;
  		}
  
  		public String bodyToString () {
  			String s = "";
  			for (int i=0; i<fParticles.size(); i++) {
  				Object particle = fParticles.elementAt (i);
  				s += particle.toString ();
  			}
  			return s;
  		}
  	}
  
  	//****************************
  	//**** Schema.ElementDecl ****
  	//****************************
  
  	public class ElementDecl	extends		AnnotatedComponent
  								implements	HasType
  	{
  		private Ref				fTypeDef = null;
  		private Ref				fEquivClass = null;
  		private Vector			fEquivElementDecls = null;
  
  		private boolean			fIsAbstract = false;
  		private boolean			fIsNullable = false;
  		private int				fFinalSet = EMPTY_SET;						// equiv class
  		private int				fBlockSet = EMPTY_SET;						// substitutions
  		private int				fValueConstraint = OPTIONAL;
  		private String			fValue = null;
  
  		//
  		// Constructor
  		//
  
  		public ElementDecl (Document doc) {
  			super (doc);
  		}
  
  		//
  		// Setters
  		//
  
  		public void setType (String name, String namespace) throws Exception {
  			if ( fTypeDef == null ) {
  				fTypeDef = new NamedRef (name, namespace);
  			} else {
  				reportGenericSchemaError ("Type def already set");
  			}
  		}
  
  		public void setType (TypeDef typeDef) throws Exception {
  			if ( fTypeDef == null ) {
  				fTypeDef = new LocalRef (typeDef);
  			} else {
  				reportGenericSchemaError ("Type def already set");
  			}
  		}
  
  		public void setSimpleType (SimpleTypeDef typeDef) throws Exception {
  			setType (typeDef);
  		}
  
  		public void setSimpleType (String name, String namespace) throws Exception {
  			setType (name, namespace);
  		}
  
  		public void setEquivClass (String name, String namespace) {
  			fEquivClass = new NamedRef (name, namespace);
  		}
  		
  		public void setAbstract (boolean isAbstract) {
  			fIsAbstract = isAbstract;
  		}
  
  		public void setNullable (boolean isNullable) {
  			fIsNullable = isNullable;
  		}
  
  		public void setFinal (int finalSet) {
  			fFinalSet = finalSet;
  		}
  
  		public void setBlock (int blockSet) {
  			fBlockSet = blockSet;
  		}
  
  		public void setDefaultValue (String defaultValue) {
  			fValueConstraint = DEFAULT;
  			fValue = defaultValue;
  		}
  		
  		public void setFixedValue (String fixedValue) {
  			fValueConstraint = DEFAULT;
  			fValue = fixedValue;
  		}
  
  		//
  		// Getters
  		//
  
  		public TypeDef getType () {
  			return fTypeDef.resolveTypeDef ();
  		}
  
  		public boolean hasTypeRef () {
  			return NamedRef.class.isInstance(fTypeDef);
  		}
  
  		public ElementDecl getEquivClass () {
  			return fEquivClass.resolveElementDecl ();
  		}
  
  		public boolean isNullable () {
  			return fIsNullable;
  		}
  
  		public boolean isAbstract () {
  			return fIsAbstract;
  		}
  
  		public String getDefaultValue () {
  			if ( fValueConstraint == DEFAULT ) {
  				return fValue;
  			} else {
  				return null;
  			}
  		}
  
  		public String getFixedValue () {
  			if ( fValueConstraint == FIXED ) {
  				return fValue;
  			} else {
  				return null;
  			}
  		}
  
  		//
  		// Validation Support
  		//
  
  		public void addEquivElementDecl (ElementDecl elementDecl) {
  			fEquivElementDecls.addElement (elementDecl);
  		}
  
  
  		//
  		// Debugging
  		//
  
  		//
  		// Debugging
  		//
  
  		public String toString () {
  
  			String s = "< " + ELT_ELEMENT;
  
  			String name = getName ();
  			if ( name != null ) {
  				s += " " + ATT_NAME + "='" + name + "'";
  			}
  
  			if ( hasTypeRef() ) {
  				s += " " + ATT_TYPE + "='" + getType().getQName() + "'";
  			} 
  
  			s += " " + ATT_ABSTRACT + "='" + (isAbstract()? "true'" : "false") + "'";
  			s += " " + ATT_NULLABLE + "='" + (isNullable()? "true'" : "false") + "'";
  
  			// default value
  
  			String defaultValue = getDefaultValue ();
  			if ( defaultValue != null ) {
  				s += " " + ATT_DEFAULT + "='" + defaultValue + "'";
  			}
  
  			// fixed value
  
  			String fixedValue = getFixedValue ();
  			if ( fixedValue != null ) {
  				s += " " + ATT_FIXED + "='" + fixedValue + "'";
  			}
  
  			// equiv class
  
  			if ( fEquivClass != null ) {
  				s += " " + ATT_EQUIVCLASS + "='" + fEquivClass.getQName () + "'";
  			}
  
  			s += annotationToString ();
  
  			// anonymous
  
  			if ( !hasTypeRef() ) {
  				getType().toString ();
  			}
  
  			return s;
  
  		}
  
  	}
  
  	//*************************
  	//**** Schema.GroupDef ****
  	//*************************
  
  	public class GroupDef		extends AnnotatedComponent
  								implements EParticleHolder
  	{
  		private int				fOrder = CHOICE;
  		private Vector			fParticles = new Vector ();
  
  
  		//
  		// Constructor
  		//
  
  		public GroupDef (Document doc) {
  			super (doc);
  		}
  
  		//
  		// Setters
  		//
  
  		public void setOrder (int order) {
  			fOrder = order;
  		}
  
  		public void add (EParticle particle) {
  			fParticles.addElement (particle);
  		}
  
  		//
  		// Getters
  		//
  
  		public int getOrder () {
  			return fOrder;
  		}
  		
  		/*
  		public void collectParticles (Hashtable particles, boolean restrict) {
  			for (int i=0; i<fParticles.size(); i++) {
  				ParticleCollector collector = (ParticleCollector)fParticles.elementAt (i);
  				collector.collectParticles (particles, restrict);
  			}
  		}
  		*/
  
  		//
  		// Debugging
  		//
  
  		public String toString () {
  			String s = "<" + ELT_GROUP;
  			String name = getName ();
  			if ( name != null ) {
  				s += " " + ATT_NAME + "='" + name + "'";
  			}	
  			s += ">\n";
  			s += annotationToString ();
  			s += bodyToString ();
  			s += "</" + ELT_GROUP + ">\n";
  			return s;
  		}
  
  		public String bodyToString () {
  			String s = "<" + ORDER_MAP[fOrder] + ">\n";
  			for (int i=0; i<fParticles.size(); i++) {
  				Object particle = fParticles.elementAt (i);
  				s += particle.toString ();
  			}
  			s += "</" + ORDER_MAP[fOrder] + ">\n";
  			return s;
  		}
  	}
  
  
  	//*****************************
  	//**** Schema.NotationDecl ****
  	//*****************************
  
  	public class NotationDecl extends AnnotatedComponent
  	{
  		private String		fSystemId = null;
  		private String		fPublicId = null;
  
  		//
  		// Constructors
  		//
  
  		public NotationDecl (Document doc) {
  			super (doc);
  		}
  
  		//
  		// Setters
  		//
  
  		public void setSystemId (String systemId) {
  			fSystemId = systemId;
  		}
  
  		public void setPublicId (String publicId) {
  			fPublicId = publicId;
  		}
  
  		//
  		// Getters
  		//
  
  		public String getSystemId () {
  			return fSystemId;
  		}
  
  		public String getPublicId () {
  			return fPublicId;
  		}
  
  		//
  		// Debugging
  		//
  
  		public String toString () {
  			String s = "<" + ELT_NOTATION;
  			s += " " + ATT_NAME + "='" + getName() + "'";
  			s += " " + ATT_SYSTEM + "='" + getSystemId() + "'";
  			s += " " + ATT_PUBLIC + "='" + getPublicId() + "'";
  			s += ">\n";
  			s += annotationToString ();
  			s += "</" + ELT_NOTATION + ">\n";
  			return s;
  		}
  
  	}
  
  
  	//**************************
  	//**** Schema.AParticle ****
  	//**************************
  
  	public abstract class AParticle extends AnnotatedComponent
  	{
  		private Ref			fComponentRef = null;
  
  		//
  		// Constructors
  		//
  
  		public AParticle (Document doc) {
  			super (doc);
  		}
  
  		//
  		// Setters
  		//
  
  		protected void setComponentRef (Ref componentRef) {
  			fComponentRef = componentRef;
  		}
  
  		//
  		// Getters
  		//
  
  		protected Ref getComponentRef () {
  			return fComponentRef;
  		}
  
  		public String getName () {
  			return fComponentRef.getName ();
  		}
  
  		public String getNamespace () {
  			return fComponentRef.getNamespace ();
  		}
  
  		// Does this particle reference a global component?
  
  		public boolean isRef () {
  			return NamedRef.class.isInstance (fComponentRef);
  		}
  	}
  
  	//***************************************
  	//**** Schema.AttributeGroupParticle ****
  	//***************************************
  
  	public class AttributeGroupParticle extends AParticle 
  	{
  		//
  		// Constructors
  		//
  
  		public AttributeGroupParticle (Document doc) {
  			super (doc);
  		}
  
  		//
  		// Setters
  		//
  
  		public void setAttributeGroupDef (AttributeGroupDef attrGroupDef) {
  			setComponentRef (new LocalRef(attrGroupDef));
  		}
  
  		public void setAttributeGroupRef (String name, String namespace) {
  			setComponentRef (new NamedRef(name, namespace));
  		}
  
  		//
  		// Getters
  		//
  
  		public AttributeGroupDef getAttributeGroupDef () {
  			return getComponentRef().resolveAttributeGroupDef ();
  		}
  
  		//
  		// Debugging
  		//
  
  		public String toString () {
  			String s = "<" + ELT_ATTRGROUP;
  			if ( isRef() ) {
  				s += ATT_REF + "='" + getComponentRef().getQName() + "'";
  			}
  			s += ">\n";
  			s += annotationToString ();
  			if ( !isRef() ) {
  				s += getAttributeGroupDef().bodyToString();
  			}
  			s += "</" + ELT_ATTRGROUP + ">\n";
  			return s;
  		}
  
  	}
  
  	//**********************************
  	//**** Schema.AttributeParticle ****
  	//**********************************
  
  	public class AttributeParticle extends AParticle
  	{
  		private int				fUse = OPTIONAL;
  		private String			fValue = null;
  
  		//
  		// Constructors
  		//
  
  		public AttributeParticle (Document doc) {
  			super (doc);
  		}
  
  		//
  		// Setters
  		//
  
  		public void setAttributeDecl (AttributeDecl attributeDecl) {
  			setComponentRef (new LocalRef(attributeDecl));
  		}
  
  		public void setAttributeRef (String name, String namespace) {
  			setComponentRef (new NamedRef(name, namespace));
  		}
  
  		public void setSimpleType (SimpleTypeDef typeDef) throws Exception {
  			getAttributeDecl().setSimpleType (typeDef);
  		}
  
  		public void setSimpleType (String name, String namespace) throws Exception {
  			getAttributeDecl().setSimpleType (name, namespace);
  		}
  
  		public void setUse (int use) {
  			// TODO: merge use with attribute decl
  			fUse = use;
  		}
  
  		public void setValue (String value) {
  			// TODO: merge value with attribute decl
  			fValue = value;
  		}
  
  		//
  		// Getters
  		//
  
  		public AttributeDecl getAttributeDecl () {
  
  			// Faults in AttributeDecl if not already there.
  
  			Ref ref = getComponentRef ();
  			if ( ref == null ) {
  				setAttributeDecl (getDocument().createAttributeDecl());
  				ref = getComponentRef ();
  			}
  			return ref.resolveAttributeDecl ();
  		}
  
  		public String getName () {
  			return getAttributeDecl().getName ();
  		}
  
  		public boolean hasTypeRef () {
  			return getAttributeDecl().hasTypeRef ();
  		}
  
  		public SimpleTypeDef getType () {
  			return getAttributeDecl().getType ();
  		}
  
  		public int getUse () {
  			if ( fUse == OPTIONAL ) {
  				return getAttributeDecl().getUse ();
  			} else {
  				return fUse;
  			}
  		}
  
  		public String getValue () {
  			if ( fValue == null ) {
  				return getAttributeDecl().getValue ();
  			} else {
  				return fValue;
  			}
  		}
  
  		//
  		// Debugging
  		//
  
  		public String toString () {
  
  			String s = "<" + ELT_ATTRIBUTE;
  
  			if ( isRef() ) {
  				s += " " + ATT_REF + "='" + getComponentRef().getQName() + "'";
  			} else {
  				s += " " + ATT_NAME + "='" + getName() + "'";
  				if ( hasTypeRef() ) {
  					s += " " + ATT_TYPE + "='" + getType().getQName() + "'";
  				}
  			}
  
  			s += " " + ATT_USE + "='" + USE_MAP[getUse()] + "'";
  			
  			String value = getValue ();
  			if ( value != null ) {
  				s += " " + ATT_VALUE + "='" + value + "'";
  			}
  
  			s += ">\n";
  			s += annotationToString ();
  
  			if ( !isRef() && !hasTypeRef() ) {
  				getType().toString ();
  			}
  
  			s += "</" + ELT_ATTRIBUTE + ">\n";
  
  			return s;
  		}
  
  
  	}
  
  	//**************************
  	//**** Schema.EParticle ****
  	//**************************
  
  	public class EParticle extends AnnotatedComponent
  	{
  		protected Ref			fComponentRef = null;
  		private int				fMinOccurs = 1;
  		private int				fMaxOccurs = 1;
  
  		//
  		// Constructors
  		//
  
  		public EParticle (Document doc) {
  			super (doc);
  		}
  
  		//
  		// Setters
  		//
  
  		protected void setComponentRef (Ref componentRef) {
  			fComponentRef = componentRef;
  		}
  
  		public void setMinOccurs (int minOccurs) {
  			fMinOccurs = minOccurs;
  		}
  
  		public void setMaxOccurs (int maxOccurs) {
  			fMaxOccurs = maxOccurs;
  		}
  
  		//
  		// Getters
  		//
  
  		protected Ref getComponentRef () {
  			return fComponentRef;
  		}
  
  		public String getName () {
  			return fComponentRef.getName ();
  		}
  
  		public String getNamespace () {
  			return fComponentRef.getNamespace ();
  		}
  
  		public int getMinOccurs () {
  			return fMinOccurs;
  		}
  
  		public int getMaxOccurs () {
  			return fMaxOccurs;
  		}
  
  		// Does this particle reference a global component?
  
  		public boolean isRef () {
  			return NamedRef.class.isInstance (fComponentRef);
  		}
  	}
  
  	//******************************
  	//**** Schema.GroupParticle ****
  	//******************************
  
  	public class GroupParticle extends EParticle
  	{
  		//
  		// Constructors
  		//
  
  		public GroupParticle (Document doc) {
  			super (doc);
  		}
  
  		//
  		// Setters
  		//
  
  		public void setGroupDef (GroupDef groupDef) {
  			setComponentRef (new LocalRef(groupDef));
  		}
  
  		public void setGroupRef (String name, String namespace) {
  			setComponentRef (new NamedRef(name, namespace));
  		}
  
  		//
  		// Getters
  		//
  
  		public GroupDef getGroupDef () {
  			return getComponentRef().resolveGroupDef ();
  		}
  
  		//
  		// Debugging
  		//
  
  		public String toString () {	
  			
  			String s = "<" + ELT_GROUP;
  
  			if ( isRef() ) {
  				s += " " + ATT_REF + "'" + getComponentRef().getQName () + "'";
  			}
  
  			s += " " + ATT_MINOCCURS + "='" + getMinOccurs() + "'";
  			s += " " + ATT_MAXOCCURS + "='" + getMaxOccurs() + "'";
  			s += ">\n";
  
  			s += annotationToString ();
  
  			if ( !isRef() ) {
  				s += getGroupDef().bodyToString ();
  			}
  
  			s += "</" + ELT_GROUP + ">\n";
  			return s;
  		}
  	}
  
  	//********************************
  	//**** Schema.ElementParticle ****
  	//********************************
  
  	public class ElementParticle	extends		EParticle
  									implements	HasType
  	{
  		// TODO: I currently don't use these.  I just use the values from the 
  		// associated elementdecl.  Need to use and merge these later.
  
  		private boolean			fIsAbstract = false;
  		private boolean			fIsNullable = false;
  		private int				fBlockSet = EMPTY_SET;	
  		private String			fDefaultValue = null;
  		private String			fFixedValue = null;
  
  		//
  		// Constructors
  		//
  
  		public ElementParticle (Document doc) {
  			super (doc);
  		}
  
  		//
  		// Setters
  		//
  
  		public void setElementDecl (ElementDecl elementDecl) {
  			setComponentRef (new LocalRef(elementDecl));
  		}
  
  		public void setElementRef (String name, String namespace) {
  			setComponentRef (new NamedRef(name, namespace));
  		}
  
  		public void setType (TypeDef typeDef) throws Exception {
  			getElementDecl().setType (typeDef);
  		}
  
  		public void setType (String name, String namespace) throws Exception {
  			getElementDecl().setType (name, namespace);
  		}
  
  		public void setSimpleType (SimpleTypeDef typeDef) throws Exception {
  			setType (typeDef);
  		}
  
  		public void setSimpleType (String name, String namespace) throws Exception {
  			setType (name, namespace);
  		}
  
  		public void setAbstract (boolean isAbstract) {
  			fIsAbstract = isAbstract;
  		}
  
  		public void setNullable (boolean isNullable) {
  			fIsNullable = isNullable;
  		}
  
  		public void setBlock (int blockSet) {
  			fBlockSet = blockSet;
  		}
  
  		public void setDefaultValue (String defaultValue) {
  			fDefaultValue = defaultValue;
  		}
  
  		public void setFixedValue (String fixedValue) {
  			fFixedValue = fixedValue;
  		}
  
  		//
  		// Getters
  		//
  
  		public ElementDecl getElementDecl () {
  			Ref ref = getComponentRef ();
  			if ( ref == null ) {
  				setElementDecl (new ElementDecl(getDocument()));
  				ref = getComponentRef ();
  			}
  			return ref.resolveElementDecl ();
  		}
  
  		public TypeDef getType () {
  			return getElementDecl().getType ();
  		}
  
  		public boolean hasTypeRef () {
  			return getElementDecl().hasTypeRef ();
  		}
  
  		public boolean isNullable () {
  			// TODO:  Merge local value with element decl
  			return getElementDecl().isNullable ();
  		}
  
  		public boolean isAbstract () {
  			return getElementDecl().isAbstract ();
  		}
  
  		public boolean canSubstituteExtension () {
  			return (fBlockSet & EXTENSION) == 0;
  		} 
  
  		public boolean canSubstituteRestriction () {
  			return (fBlockSet & RESTRICTION) == 0;
  		}
  
  		public boolean canSubstituteReproduction () {
  			return (fBlockSet & REPRODUCTION) == 0;
  		}
  
  		public String getDefaultValue () {
  			String defaultValue = getElementDecl().getDefaultValue ();
  			if ( defaultValue != null && fDefaultValue != null ) {
  				return fDefaultValue;
  			} else {
  				return defaultValue;
  			}
  		}
  
  		public String getFixedValue () {
  			String fixedValue = getElementDecl().getFixedValue ();
  			if ( fixedValue != null && fFixedValue != null ) {
  				return fFixedValue;
  			} else {
  				return fixedValue;
  			}
  		}
  
  		/*
  		public void collectElements (Hashtable elements, boolean restrict) {
  			ElementDecl elementDecl = getElementDecl ();
  			String name = elementDecl.getName ();
  			ElementDecl e = (ElementDecl)elements.get (name);
  			if ( e == null ) {
  				elements.put (name, elementDecl);
  			} else {
  				
  			}
  		}
  		*/
  
  
  		//
  		// Debugging
  		//
  
  		public String toString () {
  			String s = "<" + ELT_ELEMENT;
  
  			if ( isRef() ) {
  				s += " " + ATT_REF + "='" + getComponentRef().getQName () + "'";
  			} else {
  				s += " " + ATT_NAME + "='" + getName() + "'";
  				if ( hasTypeRef() ) {
  					s += " " + ATT_TYPE + "='" + getType().getQName() + "'";
  				}
  			}
  
  			s += " " + ATT_MINOCCURS + "='" + getMinOccurs() + "'";
  			s += " " + ATT_MAXOCCURS + "='" + getMaxOccurs() + "'";
  			s += " " + ATT_ABSTRACT + "='" + ( isAbstract()? "true" : "false" ) + "'";
  			s += " " + ATT_NULLABLE + "='" + ( isNullable()? "true" : "false" ) + "'"; 
  
  			s += " " + ATT_BLOCK + "='";
  
  			boolean extend = canSubstituteExtension ();
  			boolean restrict = canSubstituteRestriction ();
  			boolean reproduce = canSubstituteReproduction ();
  
  			if ( !extend && !restrict && !reproduce ) {
  				s += VAL_POUNDALL;
  			} else {
  				if ( !extend ) {
  					s += " " + VAL_EXTENSION;
  				}
  				if ( !restrict ) {
  					s += " " + VAL_RESTRICTION;
  				}
  				if ( !reproduce ) {
  					s += " " + VAL_REPRODUCTION;
  				}
  			}
  
  			s += "'";
  
  			if ( fDefaultValue != null ) {
  				s += " " + ATT_DEFAULT + "='" + fDefaultValue + "'";
  			}
  			if ( fFixedValue != null ) {
  				s += " " + ATT_FIXED + "='" + fFixedValue + "'";
  			}
  
  			s += ">\n";
  			s += annotationToString ();
  
  			if ( !isRef() ) {
  				s += getType().toString ();
  			}
  
  			s += "</" + ELT_ELEMENT + ">\n";
  			return s;
  		}
  
  
  	}
  
  	//
  	// Inner objects can call this to report errors
  	//
  
  	private void reportSchemaError(int major, Object args[]) {
  	    try {
      		fErrorReporter.reportError(fErrorReporter.getLocator(),
  	    							   SchemaMessageProvider.SCHEMA_DOMAIN,
  		    						   major,
  			    					   SchemaMessageProvider.MSG_NONE,
  				    				   args,
  					    			   XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
  		} catch (Exception e) {
  		    e.printStackTrace();
  		}
  	}
  
  	private void reportGenericSchemaError (String error) throws Exception {
  		reportSchemaError (SchemaMessageProvider.GenericError, new Object[] { error });
  	}
  
  
  }
  
  
  1.1                  xml-xerces/java/src/org/apache/xerces/validators/schema/SchemaImporter.java
  
  Index: SchemaImporter.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xerces" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 1999, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.xerces.validators.schema;
  
  import java.io.IOException;
  import java.util.Hashtable; // REVISIT replace
  import java.util.Vector; // REVISIT replace
  
  import org.w3c.dom.Document;
  import org.w3c.dom.DocumentType;
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXParseException;
  import org.xml.sax.EntityResolver;
  import org.xml.sax.ErrorHandler;
  import org.xml.sax.SAXException;
  
  import org.apache.xerces.dom.DocumentImpl;
  import org.apache.xerces.dom.DocumentTypeImpl;
  import org.apache.xerces.framework.XMLContentSpec;
  import org.apache.xerces.framework.XMLErrorReporter;
  import org.apache.xerces.msg.SchemaMessages;
  import org.apache.xerces.parsers.DOMParser;
  import org.apache.xerces.readers.DefaultEntityHandler;
  import org.apache.xerces.utils.StringPool;
  import org.apache.xerces.validators.common.XMLValidator;
  import org.apache.xerces.validators.common.XMLContentModel;
  import org.apache.xerces.validators.datatype.DatatypeValidator;
  import org.apache.xerces.validators.datatype.InvalidDatatypeValueException;
  import org.apache.xerces.validators.datatype.IllegalFacetException;
  import org.apache.xerces.validators.datatype.IllegalFacetValueException;
  import org.apache.xerces.validators.datatype.UnknownFacetException;
  import org.apache.xerces.validators.datatype.BooleanValidator;
  import org.apache.xerces.validators.datatype.IntegerValidator;
  import org.apache.xerces.validators.datatype.StringValidator;
  import org.apache.xerces.validators.datatype.FloatValidator;
  import org.apache.xerces.validators.datatype.DoubleValidator;
  import org.apache.xerces.validators.datatype.DecimalValidator;
  import org.apache.xerces.validators.datatype.TimeDurationValidator;
  import org.apache.xerces.validators.datatype.TimeInstantValidator;
  import org.apache.xerces.validators.datatype.BinaryValidator;
  import org.apache.xerces.validators.datatype.URIValidator;
  
  /**
   * SchemaImporter is an <font color="red"><b>experimental</b></font> implementation
   * of a validator for the W3C Schema Language.  All of its implementation is subject
   * to change.
   */
  public class SchemaImporter {
      //
      //
      //
  
  	private Schema fSchema = null;
  
      private XMLValidator fValidator = null;
      private XMLErrorReporter fErrorReporter = null;
      private DefaultEntityHandler fEntityHandler = null;
      private StringPool fStringPool = null;
      private DatatypeValidatorRegistry fDatatypeRegistry = new DatatypeValidatorRegistry();
      private int fTypeCount = 0;
      private int fGroupCount = 0;
      private int fModelGroupCount = 0;
      private int fAttributeGroupCount = 0;
      private int fDatatypeCount = 0;
      private Hashtable fForwardRefs = new Hashtable(); // REVISIT w/ more efficient structure later
      private Hashtable fAttrGroupUses = new Hashtable();
  
      // constants
  
      private static final String ELT_COMMENT = "comment";
      private static final String ELT_DATATYPEDECL = "datatype";
      private static final String ELT_ARCHETYPEDECL = "type";
      private static final String ELT_ELEMENTDECL = "element";
      private static final String ELT_GROUPDECL = "group";
      private static final String ELT_ATTRGROUPDECL = "attributeGroup";
  //    private static final String ELT_TEXTENTITYDECL = "textEntity";
  //    private static final String ELT_EXTERNALENTITYDECL = "externalEntity";
  //    private static final String ELT_UNPARSEDENTITYDECL = "unparsedEntity";
      private static final String ELT_NOTATIONDECL = "notation";
  //    private static final String ELT_REFINES = "refines";
      private static final String ELT_RESTRICTIONS = "restrictions";
      private static final String ELT_ATTRIBUTEDECL = "attribute";
      private static final String ELT_ANNOTATION = "annotation";
      private static final String ELT_ANY = "any";
      private static final String ATT_NAME = "name";
      private static final String ATT_CONTENT = "content";
      private static final String ATT_MODEL = "model";
      private static final String ATT_ORDER = "order";
      private static final String ATT_TYPE = "type";
      private static final String ATT_DEFAULT = "default";
      private static final String ATT_FIXED = "fixed";
      private static final String ATT_COLLECTION = "collection";
      private static final String ATT_REF = "ref";
      private static final String ATT_ARCHREF = "archRef";
      private static final String ATT_SCHEMAABBREV = "schemaAbbrev";
      private static final String ATT_SCHEMANAME = "schemaName";
      private static final String ATT_MINOCCURS = "minOccurs";
      private static final String ATT_MAXOCCURS = "maxOccurs";
  //    private static final String ATT_EXPORT = "export";
      private static final String ATT_SOURCE = "source";
      private static final String ATT_VALUE = "value";
      private static final String ATTVAL_ANY = "any";
      private static final String ATTVAL_MIXED = "mixed";
      private static final String ATTVAL_EMPTY = "empty";
      private static final String ATTVAL_CHOICE = "choice";
      private static final String ATTVAL_SEQ = "seq";
      private static final String ATTVAL_ALL = "all";
      private static final String ATTVAL_ELEMONLY = "elementOnly";
      private static final String ATTVAL_TEXTONLY = "textOnly";
  
      private Document fSchemaDocument = null;
  
      //
      //
      //
      public SchemaImporter(StringPool stringPool,
                            XMLErrorReporter errorReporter,
                            DefaultEntityHandler entityHandler,
                            XMLValidator validator) {
          fErrorReporter = errorReporter;
          fEntityHandler = entityHandler;
          fStringPool = stringPool;
          fValidator = validator;
          fDatatypeRegistry.initializeRegistry();
  		fSchema = new Schema (fErrorReporter, fValidator);
      }
      //
      //
      //
      public void reset(StringPool stringPool) throws Exception {
          fStringPool = stringPool;
          // need to reset the datatype registry !!
          fDatatypeRegistry = new DatatypeValidatorRegistry();
          fDatatypeRegistry.initializeRegistry();
  		fSchema = new Schema (fErrorReporter, fValidator);
      }
      //
      //
      //
      public Document getSchemaDocument() {
          return fSchemaDocument;
      }
      //
      //
      //
      private int getContentSpecHandleForElementType(int elementType) {
          return fValidator.getContentSpecHandle(fStringPool.getDeclaration(elementType));
      }
      private int getContentSpecTypeForElementType(int elementType) {
          return fValidator.getContentSpecType(fStringPool.getDeclaration(elementType));
      }
  
      // content spec node types
  
      /** Occurrence count: [0, n]. */
      private static final int CONTENTSPECNODE_ZERO_TO_N = XMLContentSpec.CONTENTSPECNODE_SEQ + 1;
  
      /** Occurrence count: [m, n]. */
      private static final int CONTENTSPECNODE_M_TO_N = CONTENTSPECNODE_ZERO_TO_N + 1;
  
      /** Occurrence count: [m, *). */
      private static final int CONTENTSPECNODE_M_OR_MORE = CONTENTSPECNODE_M_TO_N + 1;
  
      private DOMParser fSchemaParser = null;
  
      public void loadSchema(InputSource is) {
  
  
  		SchemaParser parser = new SchemaParser (fSchema);
  		try {
              parser.setEntityResolver(new Resolver());
              parser.setErrorHandler(new ErrorHandler());
              //parser.setFeature("http://xml.org/sax/features/validation", true);
  			parser.parse (is);
  		} 
  		catch (Exception e) {
              e.printStackTrace();
  			System.exit (1);
  		}
  
  
          // create parser for schema
          if (fSchemaParser == null) {
              fSchemaParser = new DOMParser() {
                  public void ignorableWhitespace(char ch[], int start, int length) {}
                  public void ignorableWhitespace(int dataIdx) {}
              };
              fSchemaParser.setEntityResolver(new Resolver());
              fSchemaParser.setErrorHandler(new ErrorHandler());
          }
  
          // parser schema file
          try {
  
              fSchemaParser.setFeature("http://xml.org/sax/features/validation", true);
              fSchemaParser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);
              fSchemaParser.parse(is);
          }
          catch (SAXException se) {
              se.getException().printStackTrace();
              System.err.println("error parsing schema file");
  //            System.exit(1);
          }
          catch (Exception e) {
              e.printStackTrace();
              System.err.println("error parsing schema file");
  //            System.exit(1);
          }
          fSchemaDocument = fSchemaParser.getDocument();
          if (fSchemaDocument == null) {
              System.err.println("error: couldn't load schema file!");
              return;
          }
  
          // traverse schema
          try {
              Element root = fSchemaDocument.getDocumentElement();
              traverseSchema(root);
          }
          catch (Exception e) {
              e.printStackTrace(System.err);
  //            System.exit(1);
          }
      }
  
      private void traverseSchema(Element root) throws Exception {
          // is there anything to do?
          if (root == null) {
              return;
          }
  
          // run through children
          for (Element child = XUtil.getFirstChildElement(root);
               child != null;
               child = XUtil.getNextSiblingElement(child)) {
              //System.out.println("child: "+child.getNodeName()+' '+child.getAttribute(ATT_NAME));
  
              //
              // Element type
              //
  
              String name = child.getNodeName();
  			if (name.equals(ELT_COMMENT)) {
  				traverseComment(child);
              } else if (name.equals(ELT_DATATYPEDECL)) {
  				traverseDatatypeDecl(child);
              } else if (name.equals(ELT_ARCHETYPEDECL)) {
  				traverseTypeDecl(child);
  			} else if (name.equals(ELT_ELEMENTDECL)) { // && child.getAttribute(ATT_REF).equals("")) {
  				traverseElementDecl(child);
  			} else if (name.equals(ELT_ATTRGROUPDECL)) {
  				traverseAttrGroup(child);
  			} else if (name.equals(ELT_GROUPDECL) && child.getAttribute(ATT_REF).equals("")) {
  				traverseGroup(child);
  			}
  
              //
              // Entities
              //
  /*
              else if (name.equals(ELT_TEXTENTITYDECL) ||
                       name.equals(ELT_EXTERNALENTITYDECL) ||
                       name.equals(ELT_UNPARSEDENTITYDECL)) {
  
                  int entityName = fStringPool.addSymbol(child.getAttribute(ATT_NAME));
  
                  if (name.equals(ELT_TEXTENTITYDECL)) {
                      int value = fStringPool.addString(child.getFirstChild().getFirstChild().getNodeValue());
                      fEntityHandler.addInternalEntityDecl(entityName, value, true);
                  }
                  else {
                      int publicId = fStringPool.addString(child.getAttribute("public"));
                      int systemId = fStringPool.addString(child.getAttribute("system"));
  
                      if (name.equals(ELT_EXTERNALENTITYDECL)) {
                          fEntityHandler.addExternalEntityDecl(entityName, publicId, systemId, true);
                      }
                      else {
                          int notationName = fStringPool.addSymbol(child.getAttribute("notation"));
                          fEntityHandler.addUnparsedEntityDecl(entityName, publicId, systemId, notationName, true);
                      }
                  }
              }
  */
              //
              // Notation
              //
  
              else if (name.equals(ELT_NOTATIONDECL)) {
  
                  int notationName = fStringPool.addSymbol(child.getAttribute(ATT_NAME));
                  int publicId = fStringPool.addString(child.getAttribute("public"));
                  int systemId = fStringPool.addString(child.getAttribute("system"));
                  fEntityHandler.addNotationDecl(notationName, publicId, systemId, true);
              }
  
          } // for each child node
  
          cleanupForwardReferences();
      } // traverseSchema(Element)
  
      /**
       * this method is going to be needed to handle any elementDecl derived constructs which
       * need to copy back attributes that haven't been declared yet.
       * right now that's just attributeGroups and types -- grrr.
       */
      private void cleanupForwardReferences() {
          for (java.util.Enumeration keys = fForwardRefs.keys(); keys.hasMoreElements();) {
              Object k = keys.nextElement();
              int ik = ((Integer) k).intValue();
              cleanupForwardReferencesTo(ik);
          }
      }
  
      private void cleanupForwardReferencesTo(int r) {
          Vector referrers = (Vector) fForwardRefs.get(new Integer(r));
          if (referrers == null) return;
  //        System.out.println("referee "+r+" csnIndex= "+getContentSpec(getElement(r)));
          for (int i = 0; i < referrers.size(); i++) {
              int ref = ((Integer) referrers.elementAt(i)).intValue();
  //            System.out.println("referrer "+referrers.elementAt(i)+ " csnIndex = "+getContentSpec(getElement(((Integer)referrers.elementAt(i)).intValue())));
  //            System.out.println("copying from "+fStringPool.toString(r)+" to "+fStringPool.toString(ref));
              fValidator.copyAtts(r, ((Integer) referrers.elementAt(i)).intValue());
  //            try {
  //                fValidator.fixupDeclaredElements(ref, r);
  //            } catch (Exception e) {
  //                System.out.println("Error while cleaning up");
  //            }
  //            cleanupForwardReferencesTo(ref);
          }
      }
  
  	private void traverseComment(Element comment) {
          return; // do nothing
  	}
  
  	private int traverseTypeDecl(Element typeDecl) throws Exception {
  		String typeName = typeDecl.getAttribute(ATT_NAME);
  		String content = typeDecl.getAttribute(ATT_CONTENT);
  		String source = typeDecl.getAttribute(ATT_SOURCE);
  
  		if (typeName.equals("")) { // gensym a unique name
  		    typeName = "http://www.apache.org/xml/xerces/internalType"+fTypeCount++;
  		}
  		
  		Element child = null;
          int contentSpecType = 0;
          int csnType = 0;
          int left = -2;
          int right = -2;
          Vector uses = new Vector();
  		
     		// skip refinement and annotations
          child = null;
  		for (child = XUtil.getFirstChildElement(typeDecl);
  		     child != null && (child.getNodeName().equals(ELT_RESTRICTIONS) ||
  		                       child.getNodeName().equals(ELT_ANNOTATION));
  		     child = XUtil.getNextSiblingElement(child)) {
      		if (child.getNodeName().equals(ELT_RESTRICTIONS))
  	    		reportSchemaError(SchemaMessageProvider.FeatureUnsupported,
  		    					  new Object [] { "Restriction" });
  	    }
  
          // if content = textonly, source is a datatype
          if (content.equals(ATTVAL_TEXTONLY)) {
              if (fDatatypeRegistry.getValidatorFor(source) == null) // must be datatype
  	    		reportSchemaError(SchemaMessageProvider.NotADatatype,
  		    					  new Object [] { source }); //REVISIT check forward refs
              //handle datatypes
              contentSpecType = fStringPool.addSymbol("DATATYPE");
              left = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF,
  									                   fStringPool.addSymbol(source),
  													   -1, false);
              
          } else {   
              contentSpecType = fStringPool.addSymbol("CHILDREN");
              csnType = XMLContentSpec.CONTENTSPECNODE_SEQ;
              boolean mixedContent = false;
              boolean elementContent = false;
              boolean textContent = false;
              left = -2;
              right = -2;
              boolean hadContent = false;
  		
              if (content.equals(ATTVAL_EMPTY)) {
                  contentSpecType = fStringPool.addSymbol("EMPTY");
                  left = -1; // no contentSpecNode needed
              } else if (content.equals(ATTVAL_MIXED) || content.equals("")) {
                  contentSpecType = fStringPool.addSymbol("MIXED");
                  mixedContent = true;
                  csnType = XMLContentSpec.CONTENTSPECNODE_CHOICE;
              } else if (content.equals(ATTVAL_ELEMONLY)) {
                  elementContent = true;
              } else if (content.equals(ATTVAL_TEXTONLY)) {
                  textContent = true;
              }
              
              if (mixedContent) {
                  // a    dd #PCDATA leaf
                  left = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF,
                                                             -1, // -1 means "#PCDATA" is name
                                                             -1, false);
              }
  
              for (;
                   child != null;
                   child = XUtil.getNextSiblingElement(child)) {
                  int index = -2;
                  hadContent = true;
                  String childName = child.getNodeName();
                  if (childName.equals(ELT_ELEMENTDECL)) {
                      if (child.getAttribute(ATT_REF).equals("") && 
                          child.getAttribute(ATT_TYPE).equals("")) { // elt decl
                          if (elementContent)   //R   EVISIT: no support for nested type declarations
                              reportSchemaError(SchemaMessageProvider.FeatureUnsupported,
                                                new Object [] { "Nesting element declarations" });
                          else
                              reportSchemaError(SchemaMessageProvider.NestedOnlyInElemOnly, null);
                      } else if (mixedContent || elementContent) {
                          if (!child.getAttribute(ATT_TYPE).equals("")) {
                              int elementNameIndex = traverseElementDecl(child);
                              index = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF,
                                                                          elementNameIndex,
                                                                          -1, false);
                          } else // ATT_REF != ""
                              index = traverseElementRef(child);
                      } else {
                          reportSchemaError(SchemaMessageProvider.EltRefOnlyInMixedElemOnly, null);
                      }
                  } else if (childName.equals(ELT_GROUPDECL)) {
                      if (elementContent) {
                          int groupNameIndex = 0;
                          if (child.getAttribute(ATT_REF).equals("")) {
                              groupNameIndex = traverseGroup(child);
                          } else
                              groupNameIndex = traverseGroupRef(child);
                          index = getContentSpecHandleForElementType(groupNameIndex);
                      } else if (!elementContent)
                          reportSchemaError(SchemaMessageProvider.OnlyInEltContent,
                                            new Object [] { "group" });
                      else // buildAll    
                          reportSchemaError(SchemaMessageProvider.OrderIsAll,
                                            new Object [] { "group" } );
                  } else if (childName.equals(ELT_ATTRIBUTEDECL) ||
                             childName.equals(ELT_ATTRGROUPDECL)) {
                      break; // attr processing is done be    low
                  } else if (childName.equals(ELT_ANY)) {
                      contentSpecType = fStringPool.addSymbol("ANY");
                      left = -1;
                  } else { // datatype qual   
                      if (source.equals(""))
                          reportSchemaError(SchemaMessageProvider.DatatypeWithType, null);
                      else
                          reportSchemaError(SchemaMessageProvider.DatatypeQualUnsupported,
                                            new Object [] { childName });
                  }
                  uses.addElement(new Integer(index));
                  if (left == -2) {
                      left = index;
                  } else if (right == -2) {
                      right = index;
                  } else {
                      left = fValidator.addContentSpecNode(csnType, left, right, false);
                      right = index;
                  }
              }
              
              if (hadContent && right != -2)
                  left = fValidator.addContentSpecNode(csnType, left, right, false);
  		
              if (mixedContent && hadContent) {
                  // set occurrence count
                  left = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE,
                                                             left, -1, false);
              }
          }
  		// stick in ElementDeclPool as a hack
  		int typeNameIndex = fStringPool.addSymbol(typeName); //REVISIT namespace clashes possible
  		int typeIndex = fValidator.addElementDecl(typeNameIndex, contentSpecType, left, false);
  
          for (int x = 0; x < uses.size(); x++)
              addUse(typeNameIndex, (Integer)uses.elementAt(x));
  
  		// (attribute | attrGroupRef)*
  		for (;
  			 child != null;
  			 child = XUtil.getNextSiblingElement(child)) {
  			String childName = child.getNodeName();
  			if (childName.equals(ELT_ATTRIBUTEDECL)) {
  				traverseAttributeDecl(child, typeIndex);
  			} else if (childName.equals(ELT_ATTRGROUPDECL) && !child.getAttribute(ATT_REF).equals("")) {
      			int index = traverseAttrGroupRef(child);
      			if (getContentSpecHandleForElementType(index) == -1) {
  					reportSchemaError(SchemaMessageProvider.FeatureUnsupported,
  									  new Object [] { "Forward References to attrGroup" });
      			    Vector v = null;
      			    Integer i = new Integer(index);
      			    if ((v = (Vector) fForwardRefs.get(i)) == null)
      			        v = new Vector();
                      v.addElement(new Integer(typeNameIndex));
      			    fForwardRefs.put(i,v);
                      addUse(typeNameIndex, index);
      			} else
          			fValidator.copyAtts(index, typeNameIndex);
  			}
  		}
  		
          return typeNameIndex;
  	}
  
  	private int traverseGroup(Element groupDecl) throws Exception {
  		String groupName = groupDecl.getAttribute(ATT_NAME);
  		String collection = groupDecl.getAttribute(ATT_COLLECTION);
  		String order = groupDecl.getAttribute(ATT_ORDER);
  		
  		if (groupName.equals("")) { // gensym a unique name
  		    groupName = "http://www.apache.org/xml/xerces/internalGroup"+fGroupCount++;
  		}
  		
  		Element child = XUtil.getFirstChildElement(groupDecl);
          while (child != null && child.getNodeName().equals(ELT_ANNOTATION))
              child = XUtil.getNextSiblingElement(child);
  
  		int contentSpecType = 0;
  		int csnType = 0;
          boolean buildAll = false;
          int allChildren[] = null;
          int allChildCount = 0;
  		
  		if (order.equals(ATTVAL_CHOICE)) {
  			csnType = XMLContentSpec.CONTENTSPECNODE_CHOICE;
  			contentSpecType = fStringPool.addSymbol("CHILDREN");
  		} else if (order.equals(ATTVAL_SEQ)) {
  			csnType = XMLContentSpec.CONTENTSPECNODE_SEQ;
  			contentSpecType = fStringPool.addSymbol("CHILDREN");
  		} else if (order.equals(ATTVAL_ALL)) {
              buildAll = true;
              allChildren = new int[((org.apache.xerces.dom.NodeImpl)groupDecl).getLength()];
              allChildCount = 0;
  		}
  		int left = -2;
  		int right = -2;
  		boolean hadContent = false;
  		int groupIndices[] = new int [((org.apache.xerces.dom.NodeImpl)groupDecl).getLength()];
  		int numGroups = 0;
  
  		for (;
  			 child != null;
  			 child = XUtil.getNextSiblingElement(child)) {
  			int index = -2;
              hadContent = true;
  			String childName = child.getNodeName();
  			if (childName.equals(ELT_ELEMENTDECL)) {
  			    if (child.getAttribute(ATT_REF).equals("") && 
                      child.getAttribute(ATT_TYPE).equals("")) { //elt decl
  					reportSchemaError(SchemaMessageProvider.FeatureUnsupported,
  									  new Object [] { "Nesting element declarations" });
                  } else {
                      if (!child.getAttribute(ATT_TYPE).equals("")) {
      			       int elementNameIndex = traverseElementDecl(child);
      			       index = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF,
      			                                                   elementNameIndex,
      			                                                   -1, false);
      			       
                      } else {
                          index = traverseElementRef(child); 
                      }
                  }
  			} else if (childName.equals(ELT_GROUPDECL)) {
  			    if (!buildAll) {
      			    int groupNameIndex = traverseGroup(child);
  	    			groupIndices[numGroups++] = groupNameIndex;
  		    		index = getContentSpecHandleForElementType(groupNameIndex);
  		    	} else
  					reportSchemaError(SchemaMessageProvider.OrderIsAll,
  									  new Object [] { "group" } );
  			} else {
  				reportSchemaError(SchemaMessageProvider.GroupContentRestricted,
  								  new Object [] { "group", childName });
  			}
  			if (buildAll) {
  			    allChildren[allChildCount++] = index;
  			} else if (left == -2) {
  				left = index;
  			} else if (right == -2) {
  				right = index;
  			} else {
     				left = fValidator.addContentSpecNode(csnType, left, right, false);
      			right = index;
     			}
  		}
  		if (buildAll) {
  		    left = buildAllModel(allChildren,allChildCount);
  		} else {
  			if (hadContent && right != -2)
  				left = fValidator.addContentSpecNode(csnType, left, right, false);
  		}
  		left = expandContentModel(left, groupDecl);
  	
  		// stick in ElementDeclPool as a hack
  		int groupNameIndex = fStringPool.addSymbol(groupName); //REVISIT namespace clashes possible
  		int groupIndex = fValidator.addElementDecl(groupNameIndex, contentSpecType, left, false);
  
          return groupNameIndex;
  	}
  
  	private int traverseGroupRef(Element groupRef) {
  	    String name = groupRef.getAttribute(ATT_REF);
  	    int index = fStringPool.addSymbol(name);
  	    return index;
  	}
  
  	public int traverseDatatypeDecl(Element datatypeDecl) throws Exception {
  		int newTypeName;
  		
   		if (datatypeDecl.getAttribute(ATT_NAME).equals("")) {
      		String newTypeString = "http://www.apache.org/xml/xerces/internalDatatype"+fGroupCount++;
  		    newTypeName = fStringPool.addSymbol(newTypeString);
  	 	} else
      		newTypeName = fStringPool.addSymbol(datatypeDecl.getAttribute(ATT_NAME));
  		int basetype = fStringPool.addSymbol(datatypeDecl.getAttribute(ATT_SOURCE));
  
  		// check that base type is defined
  		//REVISIT: how do we do the extension mechanism? hardwired type name?
  		DatatypeValidator baseValidator = fDatatypeRegistry.getValidatorFor(datatypeDecl.getAttribute(ATT_SOURCE));
  		if (baseValidator == null) {
  			reportSchemaError(SchemaMessageProvider.UnknownBaseDatatype,
  							  new Object [] { datatypeDecl.getAttribute(ATT_SOURCE), datatypeDecl.getAttribute(ATT_NAME) });
  			return -1;
  		}
  
  		// build facet list
  		int numFacets = 0;
  		int numEnumerationLiterals = 0;
  		Hashtable facetData = new Hashtable();
  		Vector enumData = new Vector();
  
          // Skip annotations
  		Node facet = datatypeDecl.getFirstChild();
  		while (facet != null && facet.getNodeName().equals(ELT_ANNOTATION))
  		    facet = facet.getNextSibling();
  		while (facet != null) {
  			if (facet.getNodeType() == Node.ELEMENT_NODE) {
  			    Element facetElt = (Element) facet;
  				numFacets++;
      			if (facetElt.getNodeName().equals(DatatypeValidator.ENUMERATION)) {
  					numEnumerationLiterals++;
  					enumData.addElement(facetElt.getAttribute(ATT_VALUE));
  				} else {
  					facetData.put(facetElt.getNodeName(),facetElt.getAttribute(ATT_VALUE));
  				}
  			}
  			facet = facet.getNextSibling();
  		}
  		if (numEnumerationLiterals > 0) {
  			facetData.put(DatatypeValidator.ENUMERATION, enumData);
  		}
  
  		// create & register validator for "generated" type if it doesn't exist
  		try {
  			DatatypeValidator newValidator = (DatatypeValidator) baseValidator.getClass().newInstance();
  			if (numFacets > 0)
  				newValidator.setFacets(facetData);
  			fDatatypeRegistry.addValidator(fStringPool.toString(newTypeName),newValidator);
  		} catch (Exception e) {
  			reportSchemaError(SchemaMessageProvider.DatatypeError,
  							  new Object [] { e.getMessage() });
  		}
          return newTypeName;
  	}
  
  	private int traverseElementDecl(Element elementDecl) throws Exception {
  		int contentSpecType      = -1;
  		int contentSpecNodeIndex = -1;
          int typeNameIndex = -1;
  
  		String name = elementDecl.getAttribute(ATT_NAME);
  		String ref = elementDecl.getAttribute(ATT_REF);
  		String type = elementDecl.getAttribute(ATT_TYPE);
  		String minOccurs = elementDecl.getAttribute(ATT_MINOCCURS);
  		String maxOccurs = elementDecl.getAttribute(ATT_MAXOCCURS);
  		String dflt = elementDecl.getAttribute(ATT_DEFAULT);
  		String fixed = elementDecl.getAttribute(ATT_FIXED);
  
          int attrCount = 0;
  		if (!ref.equals("")) attrCount++;
  		if (!type.equals("")) attrCount++;
  		//REVISIT top level check for ref & archref
  		if (attrCount > 1)
  			reportSchemaError(SchemaMessageProvider.OneOfTypeRefArchRef, null);
  		
  		if (!ref.equals("")) {
  		    if (XUtil.getFirstChildElement(elementDecl) != null)
  				reportSchemaError(SchemaMessageProvider.NoContentForRef, null);
  		   	int typeName = fStringPool.addSymbol(ref);
  		   	contentSpecNodeIndex = getContentSpecHandleForElementType(typeName);
  		   	contentSpecType = getContentSpecTypeForElementType(typeName);
  
  		   	int elementNameIndex = fStringPool.addSymbol(name);
              int elementIndex = -1;
  
  		   	if (contentSpecNodeIndex == -1) {
  		   	    contentSpecType = XMLContentSpec.CONTENTSPECNODE_LEAF;
              	contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF,
  	        							                                   elementNameIndex, -1, false);
                  fValidator.addElementDecl(elementNameIndex, contentSpecType, contentSpecNodeIndex, true);
  				reportSchemaError(SchemaMessageProvider.FeatureUnsupported,
  								  new Object [] { "Forward references to archetypes" });
      			Vector v = null;
      			Integer i = new Integer(typeName);
      			if ((v = (Vector) fForwardRefs.get(i)) == null)
      			     v = new Vector();
                  v.addElement(new Integer(elementNameIndex));
      			fForwardRefs.put(i,v);
      			addUse(elementNameIndex, typeName);
  		   	} else {
                  fValidator.addElementDecl(elementNameIndex, contentSpecType, contentSpecNodeIndex, true);
                  // copy up attribute decls from type object
                  fValidator.copyAtts(typeName, elementNameIndex);
              }
  		    return elementNameIndex;
  		}
  		
  		// element has a single child element, either a datatype or a type, null if primitive
  		Element content = XUtil.getFirstChildElement(elementDecl);
          while (content != null && content.getNodeName().equals(ELT_ANNOTATION))
              content = XUtil.getNextSiblingElement(content);
  
  		if (content != null) {
  			String contentName = content.getNodeName();
  			if (contentName.equals(ELT_ARCHETYPEDECL)) {
  				typeNameIndex = traverseTypeDecl(content);
  				contentSpecNodeIndex = getContentSpecHandleForElementType(typeNameIndex);
  				contentSpecType = getContentSpecTypeForElementType(typeNameIndex);
  			} else if (contentName.equals(ELT_DATATYPEDECL)) {
  				reportSchemaError(SchemaMessageProvider.FeatureUnsupported,
  								  new Object [] { "Nesting datatype declarations" });
  				// contentSpecNodeIndex = traverseDatatypeDecl(content);
  				// contentSpecType = fStringPool.addSymbol("DATATYPE");
  			} else if (!type.equals("")) { // datatype
  				contentSpecType = fStringPool.addSymbol("DATATYPE");
  
  				// set content spec node index to leaf
  				contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF,
  																		   fStringPool.addSymbol(content.getAttribute(ATT_NAME)),
  																		   -1, false);
  				// set occurrance count
  				contentSpecNodeIndex = expandContentModel(contentSpecNodeIndex, content);
  			} else if (type.equals("")) { // "untyped" leaf
  			    // untyped leaf element decl
  	    		contentSpecType = fStringPool.addSymbol("CHILDREN");
  
      			// add leaf
  				int leftIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF,
  																	fStringPool.addSymbol(content.getAttribute(ATT_NAME)),
  																	-1, false);
  
      			// set occurrence count
  	    		contentSpecNodeIndex = expandContentModel(contentSpecNodeIndex, content);
  			} else {
  				System.out.println("unhandled case in element decl code");
  			}
  		} else if (!type.equals("")) { // type specified in attribute, not content
  			contentSpecType = fStringPool.addSymbol("DATATYPE");
  
  			// set content spec node index to leaf
  			contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF,
  																	   fStringPool.addSymbol(type),
  																	   -1, false);
  			// set occurrance count
  			contentSpecNodeIndex = expandContentModel(contentSpecNodeIndex, elementDecl);
  		}
  
  		//
  		// Create element decl
  		//
  
  		int elementNameIndex     = fStringPool.addSymbol(elementDecl.getAttribute(ATT_NAME));
  
  		// add element decl to pool
  		int elementIndex = fValidator.addElementDecl(elementNameIndex, contentSpecType, contentSpecNodeIndex, true);
  //        System.out.println("elementIndex:"+elementIndex+" "+elementDecl.getAttribute(ATT_NAME)+" eltType:"+elementName+" contentSpecType:"+contentSpecType+
  //                           " SpecNodeIndex:"+ contentSpecNodeIndex);
  
          // copy up attribute decls from type object
          if (typeNameIndex != -1)
              fValidator.copyAtts(typeNameIndex, elementNameIndex);
  
          return elementNameIndex;
  	}
  
      private int traverseElementRef(Element elementRef) {
          String elementName = elementRef.getAttribute(ATT_REF);
          int elementTypeIndex = fStringPool.addSymbol(elementName);
          int contentSpecNodeIndex = 0;
          try {
          	contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF,
  	    							                                   elementTypeIndex, -1, false);
              contentSpecNodeIndex = expandContentModel(contentSpecNodeIndex, elementRef);
          } catch (Exception e) {
              //REVISIT: integrate w/ error handling
              e.printStackTrace();
          }
          return contentSpecNodeIndex;
      }
  
  	//REVISIT: elementIndex API is ugly
  	private void traverseAttributeDecl(Element attrDecl, int elementIndex) throws Exception {
  		// attribute name
  		int attName = fStringPool.addSymbol(attrDecl.getAttribute(ATT_NAME));
  
  		// attribute type
  		int attType = -1;
  		int enumeration = -1;
  		String datatype = attrDecl.getAttribute(ATT_TYPE);
  		if (datatype.equals("")) {
  		    Element child = XUtil.getFirstChildElement(attrDecl);
  		    while (child != null && !child.getNodeName().equals(ELT_DATATYPEDECL))
  		        child = XUtil.getNextSiblingElement(child);
  		    if (child != null && child.getNodeName().equals(ELT_DATATYPEDECL)) {
  		        attType = fStringPool.addSymbol("DATATYPE");
  		        enumeration = traverseDatatypeDecl(child);
  		    } else 
      			attType = fStringPool.addSymbol("CDATA");
  		} else {
  			if (datatype.equals("string")) {
  				attType = fStringPool.addSymbol("CDATA");
  			} else if (datatype.equals("ID")) {
  				attType = fStringPool.addSymbol("ID");
  			} else if (datatype.equals("IDREF")) {
  				attType = fStringPool.addSymbol("IDREF");
  			} else if (datatype.equals("IDREFS")) {
  				attType = fStringPool.addSymbol("IDREFS");
  			} else if (datatype.equals("ENTITY")) {
  				attType = fStringPool.addSymbol("ENTITY");
  			} else if (datatype.equals("ENTITIES")) {
  				attType = fStringPool.addSymbol("ENTITIES");
  			} else if (datatype.equals("NMTOKEN")) {
  				Element e = XUtil.getFirstChildElement(attrDecl, "enumeration");
  				if (e == null) {
  					attType = fStringPool.addSymbol("NMTOKEN");
  				} else {
  					attType = fStringPool.addSymbol("ENUMERATION");
  					enumeration = fStringPool.startStringList();
  					for (Element literal = XUtil.getFirstChildElement(e, "literal");
  						 literal != null;
  						 literal = XUtil.getNextSiblingElement(literal, "literal")) {
  			    		int stringIndex = fStringPool.addSymbol(literal.getFirstChild().getNodeValue());
  						fStringPool.addStringToList(enumeration, stringIndex);
  					}
  					fStringPool.finishStringList(enumeration);
  				}
  			} else if (datatype.equals("NMTOKENS")) {
  				attType = fStringPool.addSymbol("NMTOKENS");
  			} else if (datatype.equals(ELT_NOTATIONDECL)) {
  				attType = fStringPool.addSymbol("NOTATION");
  			} else { // REVISIT: Danger: assuming all other ATTR types are datatypes
  				//REVISIT check against list of validators to ensure valid type name
  				attType = fStringPool.addSymbol("DATATYPE");
  				enumeration = fStringPool.addSymbol(datatype);
  			}
  		}
  
  		// attribute default type
  		int attDefaultType = -1;
  		int attDefaultValue = -1;
  		boolean required = attrDecl.getAttribute("minOccurs").equals("1");
  		if (required) {
  			attDefaultType = fStringPool.addSymbol("#REQUIRED");
  		} else {
  			String fixed = attrDecl.getAttribute(ATT_FIXED);
  			if (!fixed.equals("")) {
  				attDefaultType = fStringPool.addSymbol("#FIXED");
  				attDefaultValue = fStringPool.addString(fixed);
  			} else {
  				// attribute default value
  				String defaultValue = attrDecl.getAttribute(ATT_DEFAULT);
  				if (!defaultValue.equals("")) {
  					attDefaultType = fStringPool.addSymbol("");
  					attDefaultValue = fStringPool.addString(defaultValue);
  				} else {
  					attDefaultType = fStringPool.addSymbol("#IMPLIED");
  				}
  			}
  			// check default value is valid for the datatype.
  			if (attType == fStringPool.addSymbol("DATATYPE") && attDefaultValue != -1) {
          		try { // REVISIT - integrate w/ error handling
                      String type = fStringPool.toString(enumeration);
                      DatatypeValidator v = fDatatypeRegistry.getValidatorFor(type);
                      if (v != null)
                          v.validate(fStringPool.toString(attDefaultValue));
                      else
  						reportSchemaError(SchemaMessageProvider.NoValidatorFor,
  										  new Object [] { type });
                  } catch (InvalidDatatypeValueException idve) {
  					reportSchemaError(SchemaMessageProvider.IncorrectDefaultType,
  									  new Object [] { attrDecl.getAttribute(ATT_NAME), idve.getMessage() });
                  } catch (Exception e) {
                      e.printStackTrace();
                      System.out.println("Internal error in attribute datatype validation");
                  }
              }
  		}
  
  		// add attribute to element decl pool
  		fValidator.addAttDef(elementIndex, attName, attType, enumeration, attDefaultType, attDefaultValue, true);
  	}
  
  	private int traverseAttrGroup(Element attrGroupDecl) throws Exception {
  
  		String attrGroupName = attrGroupDecl.getAttribute(ATT_NAME);
  		
  		if (attrGroupName.equals("")) { // gensym a unique name
  		    attrGroupName = "http://www.apache.org/xml/xerces/internalGroup"+fGroupCount++;
  		}
  		
  		Element child = XUtil.getFirstChildElement(attrGroupDecl);
          while (child != null && child.getNodeName().equals(ELT_ANNOTATION))
              child = XUtil.getNextSiblingElement(child);
  
  		int groupIndices[] = new int [((org.apache.xerces.dom.NodeImpl)attrGroupDecl).getLength()];
  		int numGroups = 0;
  
  		for (;
  			 child != null;
  			 child = XUtil.getNextSiblingElement(child)) {
  			String childName = child.getNodeName();
  			if (childName.equals(ELT_ATTRGROUPDECL) && !child.getAttribute(ATT_REF).equals("")) {
  			    groupIndices[numGroups++] = traverseAttrGroupRef(child);
  			    if (getContentSpecHandleForElementType(groupIndices[numGroups-1]) == -1) {
  					reportSchemaError(SchemaMessageProvider.FeatureUnsupported,
  									  new Object [] { "Forward reference to AttrGroup" });
  			    }
  			} else if (childName.equals(ELT_ATTRIBUTEDECL)) {
                  continue;
     			} else {
  				reportSchemaError(SchemaMessageProvider.IllegalAttContent,
  								  new Object [] { childName });
     			}
  		}
  	
  		// stick in ElementDeclPool as a hack
  		int attrGroupNameIndex = fStringPool.addSymbol(attrGroupName); //REVISIT namespace clashes possible
  		int attrGroupIndex = fValidator.addElementDecl(attrGroupNameIndex, 0, 0, false);
  //        System.out.println("elementIndex:"+groupIndex+" "+groupName+" eltType:"+groupNameIndex+" SpecType:"+contentSpecType+
  //                           " SpecNodeIndex:"+ left);
  
  		// (attribute | attrGroupRef)*
  		for (child = XUtil.getFirstChildElement(attrGroupDecl);  // start from the beginning to just do attrs
  			 child != null;
  			 child = XUtil.getNextSiblingElement(child)) {
  			String childName = child.getNodeName();
  			if (childName.equals(ELT_ATTRIBUTEDECL)) {
  				traverseAttributeDecl(child, attrGroupIndex);
  			} else if (childName.equals(ELT_ATTRGROUPDECL)) {
      			int index = traverseAttrGroupRef(child);
      			if (getContentSpecHandleForElementType(index) == -1) {
  					reportSchemaError(SchemaMessageProvider.FeatureUnsupported,
  									  new Object [] { "Forward reference to AttrGroup" });
      			    Vector v = null;
      			    Integer i = new Integer(index);
      			    if ((v = (Vector) fForwardRefs.get(i)) == null)
      			        v = new Vector();
                      v.addElement(new Integer(attrGroupNameIndex));
      			    fForwardRefs.put(i,v);
      			    addUse(attrGroupNameIndex, index);
      			} else
      			    groupIndices[numGroups++] = getContentSpecHandleForElementType(index);
  			}
  		}
  		
          // copy up attribute decls from nested groups
  		for (int i = 0; i < numGroups; i++) {
              fValidator.copyAtts(groupIndices[i], attrGroupNameIndex);
          }
  
          return attrGroupNameIndex;
  	}
  
  	private int traverseAttrGroupRef(Element attrGroupRef) {
  	    String name = attrGroupRef.getAttribute(ATT_REF);
  	    int index = fStringPool.addSymbol(name);
          return index;
  	}
  	
  	private void addUse(int def, int use) {
          addUse(def, new Integer(use));
  	}
  
  	private void addUse(int def, Integer use) {
          Vector v = (Vector) fAttrGroupUses.get(new Integer(def));
          if (v == null) v = new Vector();
      		 v.addElement(use);
  	}
  
      /** builds the all content model */
      private int buildAllModel(int children[], int count) throws Exception {
  
          // build all model
          if (count > 1) {
  
              // create and initialize singletons
              XMLContentSpec.Node choice = new XMLContentSpec.Node();
  
              choice.type = XMLContentSpec.CONTENTSPECNODE_CHOICE;
              choice.value = -1;
              choice.otherValue = -1;
  
              // build all model
              sort(children, 0, count);
              int index = buildAllModel(children, 0, choice);
  
              return index;
          }
  
          if (count > 0) {
              return children[0];
          }
  
          return -1;
      }
  
      /** Builds the all model. */
      private int buildAllModel(int src[], int offset,
                                XMLContentSpec.Node choice) throws Exception {
  
          // swap last two places
          if (src.length - offset == 2) {
              int seqIndex = createSeq(src);
              if (choice.value == -1) {
                  choice.value = seqIndex;
              }
              else {
                  if (choice.otherValue != -1) {
                      choice.value = fValidator.addContentSpecNode(choice.type, choice.value, choice.otherValue, false);
                  }
                  choice.otherValue = seqIndex;
              }
              swap(src, offset, offset + 1);
              seqIndex = createSeq(src);
              if (choice.value == -1) {
                  choice.value = seqIndex;
              }
              else {
                  if (choice.otherValue != -1) {
                      choice.value = fValidator.addContentSpecNode(choice.type, choice.value, choice.otherValue, false);
                  }
                  choice.otherValue = seqIndex;
              }
              return fValidator.addContentSpecNode(choice.type, choice.value, choice.otherValue, false);
          }
  
          // recurse
          for (int i = offset; i < src.length - 1; i++) {
              choice.value = buildAllModel(src, offset + 1, choice);
              choice.otherValue = -1;
              sort(src, offset, src.length - offset);
              shift(src, offset, i + 1);
          }
  
          int choiceIndex = buildAllModel(src, offset + 1, choice);
          sort(src, offset, src.length - offset);
  
          return choiceIndex;
  
      } // buildAllModel(int[],int,ContentSpecNode,ContentSpecNode):int
  
      /** Creates a sequence. */
      private int createSeq(int src[]) throws Exception {
  
          int left = src[0];
          int right = src[1];
  
          for (int i = 2; i < src.length; i++) {
              left = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ,
                                                         left, right, false);
              right = src[i];
          }
  
          return fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ,
                                                     left, right, false);
  
      } // createSeq(int[]):int
  
      /** Shifts a value into position. */
      private void shift(int src[], int pos, int offset) {
  
          int temp = src[offset];
          for (int i = offset; i > pos; i--) {
              src[i] = src[i - 1];
          }
          src[pos] = temp;
  
      } // shift(int[],int,int)
  
      /** Simple sort. */
      private void sort(int src[], final int offset, final int length) {
  
          for (int i = offset; i < offset + length - 1; i++) {
              int lowest = i;
              for (int j = i + 1; j < offset + length; j++) {
                  if (src[j] < src[lowest]) {
                      lowest = j;
                  }
              }
              if (lowest != i) {
                  int temp = src[i];
                  src[i] = src[lowest];
                  src[lowest] = temp;
              }
          }
  
      } // sort(int[],int,int)
  
      /** Swaps two values. */
      private void swap(int src[], int i, int j) {
  
          int temp = src[i];
          src[i] = src[j];
          src[j] = temp;
  
      } // swap(int[],int,int)
  
      /***
      private void print(int indexes[], int offset, boolean mark) {
  
          for (int i = 0; i < indexes.length; i++) {
              System.out.print(offset==i?'.':' ');
              System.out.print(indexes[i]);
          }
          if (mark) {
              System.out.print(" *");
          }
          System.out.println();
  
      } // print(int[],int,boolean)
      /***/
  
      /** Builds the children content model. */
  /*    private int buildChildrenModel(Element model, int type) throws Exception {
  
          // is there anything to do?
          if (model == null) {
              return -1;
          }
  
          // fill parent node
          int parentValue = -1;
          int parentOtherValue = -1;
  
          // build content model bottom-up
          int index = -1;
          for (Element child = XUtil.getFirstChildElement(model);
               child != null;
               child = XUtil.getNextSiblingElement(child)) {
  
              //
              // leaf
              //
  
              String childName = child.getNodeName();
              if (childName.equals("elementTypeRef")) {
  
                  // add element name to symbol table
                  String elementType = child.getAttribute(ATT_NAME);
                  int elementTypeIndex = fStringPool.addSymbol(elementType);
  
                  // create leaf node
                  index = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF,
                                                              elementTypeIndex, -1, false);
  
                  // set occurrence count
                  index = expandContentModel(index, child);
  
              }
  
              //
              // all
              //
  
              else if (childName.equals(ATTVAL_ALL)) {
  
                  index = buildAllModel(child);
  
              }
  
              //
              // choice or sequence
              //
  
              else {
                  int childType = childName.equals(ATTVAL_CHOICE)
                                ? XMLContentSpec.CONTENTSPECNODE_CHOICE
                                : XMLContentSpec.CONTENTSPECNODE_SEQ;
                  index = buildChildrenModel(child, childType);
              }
  
              // add to parent node
              if (parentValue == -1) {
                  parentValue = index;
              }
              else if (parentOtherValue == -1) {
                  parentOtherValue = index;
              }
              else {
                  parentValue = fValidator.addContentSpecNode(type, parentValue, parentOtherValue, false);
                  parentOtherValue = index;
              }
  
          } // for all children
  
          // set model type
          index = fValidator.addContentSpecNode(type, parentValue, parentOtherValue, false);
  
          // set occurrence count
          index = expandContentModel(index, model);
  
          // return last content spec node
          return index;
  
      } // buildChildrenModel(Element,int):int
  */
      private int expandContentModel(int contentSpecNodeIndex, Element element) throws Exception {
  
          // set occurrence count
          int occurs = getOccurrenceCount(element);
          int m = 1, n = 1;
          if (!isSimpleOccurrenceCount(occurs)) {
              try { m = Integer.parseInt(element.getAttribute(ATT_MINOCCURS)); }
              catch (NumberFormatException e) {
  				reportSchemaError(SchemaMessageProvider.ValueNotInteger,
  								  new Object [] { ATT_MINOCCURS });
  			}
              try { n = Integer.parseInt(element.getAttribute(ATT_MAXOCCURS)); }
              catch (NumberFormatException e) {
  				reportSchemaError(SchemaMessageProvider.ValueNotInteger,
  								  new Object [] { ATT_MAXOCCURS });
  			}
          }
  
  		switch (occurs) {
  
              //
              // +
              //
  
              case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE: {
                  //System.out.println("occurs = +");
                  contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE,
                                                              contentSpecNodeIndex, -1, false);
                  break;
              }
  
              //
              // *
              //
  
              case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE: {
                  //System.out.println("occurs = *");
                  contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE,
                                                              contentSpecNodeIndex, -1, false);
                  break;
              }
  
              //
              // ?
              //
  
              case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE: {
                  //System.out.println("occurs = ?");
                  contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE,
                                                              contentSpecNodeIndex, -1, false);
                  break;
              }
  
              //
              // M -> *
              //
  
              case CONTENTSPECNODE_M_OR_MORE: {
                  //System.out.println("occurs = "+m+" -> *");
  
                  // create sequence node
                  int value = contentSpecNodeIndex;
                  int otherValue = -1;
  
                  // add required number
                  for (int i = 1; i < m; i++) {
                      if (otherValue != -1) {
                          value = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ,
                                                                      value, otherValue, false);
                      }
                      otherValue = contentSpecNodeIndex;
                  }
  
                  // create optional content model node
                  contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE,
                                                              contentSpecNodeIndex, -1, false);
  
                  // add optional part
                  if (otherValue != -1) {
                      value = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ,
                                                                  value, otherValue, false);
                  }
                  otherValue = contentSpecNodeIndex;
  
                  // set expanded content model index
                  contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ,
                                                              value, otherValue, false);
                  break;
              }
  
              //
              // M -> N
              //
  
              case CONTENTSPECNODE_M_TO_N: {
                  //System.out.println("occurs = "+m+" -> "+n);
  
                  // create sequence node
                  int value = contentSpecNodeIndex;
                  int otherValue = -1;
  
                  // add required number
                  for (int i = 1; i < m; i++) {
                      if (otherValue != -1) {
                          value = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ,
                                                                      value, otherValue, false);
                      }
                      otherValue = contentSpecNodeIndex;
                  }
  
                  // create optional content model node
                  contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE,
                                                              contentSpecNodeIndex, -1, false);
  
                  // add optional number
                  for (int i = n; i > m; i--) {
                      if (otherValue != -1) {
                          value = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ,
                                                                          value, otherValue, false);
                      }
                      otherValue = contentSpecNodeIndex;
                  }
  
                  // set expanded content model index
                  contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ,
                                                              value, otherValue, false);
                  break;
              }
  
              //
              // 0 -> N
              //
  
              case CONTENTSPECNODE_ZERO_TO_N: {
                  //System.out.println("occurs = 0 -> "+n);
  
                  // create optional content model node
                  contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE,
                                                              contentSpecNodeIndex, -1, false);
  
                  int value = contentSpecNodeIndex;
                  int otherValue = -1;
  
                  // add optional number
                  for (int i = 1; i < n; i++) {
                      if (otherValue != -1) {
                          value = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ,
                                                                      value, otherValue, false);
                      }
                      otherValue = contentSpecNodeIndex;
                  }
  
                  // set expanded content model index
                  contentSpecNodeIndex = fValidator.addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_SEQ,
                                                              value, otherValue, false);
                  break;
              }
  
          } // switch
  
          //System.out.println("content = "+getContentSpecNodeAsString(contentSpecNodeIndex));
          return contentSpecNodeIndex;
  
      } // expandContentModel(int,int,int,int):int
  
      private boolean isSimpleOccurrenceCount(int occurs) {
          return occurs == -1 ||
                 occurs == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE ||
                 occurs == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE ||
                 occurs == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE;
      }
  
      private int getOccurrenceCount(Element element) {
  
          String minOccur = element.getAttribute(ATT_MINOCCURS);
          String maxOccur = element.getAttribute(ATT_MAXOCCURS);
  
          if (minOccur.equals("0")) {
              if (maxOccur.equals("1") || maxOccur.length() == 0) {
                  return XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE;
              }
              else if (maxOccur.equals("*")) {
                  return XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE;
              }
              else {
                  return CONTENTSPECNODE_ZERO_TO_N;
              }
          }
          else if (minOccur.equals("1") || minOccur.length() == 0) {
              if (maxOccur.equals("*")) {
                  return XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE;
              }
              else if (!maxOccur.equals("1") && maxOccur.length() > 0) {
                  return CONTENTSPECNODE_M_TO_N;
              }
          }
          else {
              if (maxOccur.equals("*")) {
                  return CONTENTSPECNODE_M_OR_MORE;
              }
              else {
                  return CONTENTSPECNODE_M_TO_N;
              }
          }
  
          // exactly one
          return -1;
      }
  
  	private void reportSchemaError(int major, Object args[]) throws Exception {
  //	    try {
      		fErrorReporter.reportError(fErrorReporter.getLocator(),
  	    							   SchemaMessageProvider.SCHEMA_DOMAIN,
  		    						   major,
  			    					   SchemaMessageProvider.MSG_NONE,
  				    				   args,
  					    			   XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
  //		} catch (Exception e) {
  //		    e.printStackTrace();
  //		}
  	}
  
      //
      // Classes
      //
  
      static class Resolver implements EntityResolver {
  
          private static final String SYSTEM[] = {
              "http://www.w3.org/TR/2000/WD-xmlschema-1-20000225/structures.dtd",
              "http://www.w3.org/TR/2000/WD-xmlschema-2-20000225/datatypes.dtd",
              "http://www.w3.org/TR/2000/WD-xmlschema-1-20000225/versionInfo.ent",
              };
          private static final String PATH[] = {
              "structures.dtd",
              "datatypes.dtd",
              "versionInfo.ent",
              };
  
          public InputSource resolveEntity(String publicId, String systemId)
              throws IOException {
  
              // looking for the schema DTDs?
              for (int i = 0; i < SYSTEM.length; i++) {
                  if (systemId.equals(SYSTEM[i])) {
                      InputSource source = new InputSource(getClass().getResourceAsStream(PATH[i]));
                      source.setPublicId(publicId);
                      source.setSystemId(systemId);
                      return source;
                  }
              }
  
              // use default resolution
              return null;
  
          } // resolveEntity(String,String):InputSource
  
      } // class Resolver
  
      static class ErrorHandler implements org.xml.sax.ErrorHandler {
  
          /** Warning. */
          public void warning(SAXParseException ex) {
              System.err.println("[Warning] "+
                                 getLocationString(ex)+": "+
                                 ex.getMessage());
          }
  
          /** Error. */
          public void error(SAXParseException ex) {
              System.err.println("[Error] "+
                                 getLocationString(ex)+": "+
                                 ex.getMessage());
          }
  
          /** Fatal error. */
          public void fatalError(SAXParseException ex) throws SAXException {
              System.err.println("[Fatal Error] "+
                                 getLocationString(ex)+": "+
                                 ex.getMessage());
              throw ex;
          }
  
          //
          // Private methods
          //
  
          /** Returns a string of the location. */
          private String getLocationString(SAXParseException ex) {
              StringBuffer str = new StringBuffer();
  
              String systemId_ = ex.getSystemId();
              if (systemId_ != null) {
                  int index = systemId_.lastIndexOf('/');
                  if (index != -1)
                      systemId_ = systemId_.substring(index + 1);
                  str.append(systemId_);
              }
              str.append(':');
              str.append(ex.getLineNumber());
              str.append(':');
              str.append(ex.getColumnNumber());
  
              return str.toString();
  
          } // getLocationString(SAXParseException):String
      }
  
      class DatatypeValidatorRegistry {
          Hashtable fRegistry = new Hashtable();
  
          String integerSubtypeTable[][] = {
              { "non-negative-integer", DatatypeValidator.MININCLUSIVE , "0"},
              { "positive-integer", DatatypeValidator.MININCLUSIVE, "1"},
              { "non-positive-integer", DatatypeValidator.MAXINCLUSIVE, "0"},
              { "negative-integer", DatatypeValidator.MAXINCLUSIVE, "-1"}
          };
  
          void initializeRegistry() {
              Hashtable facets = null;
              fRegistry.put("boolean", new BooleanValidator());
              DatatypeValidator integerValidator = new IntegerValidator();
              fRegistry.put("integer", integerValidator);
              fRegistry.put("string", new StringValidator());
              fRegistry.put("decimal", new DecimalValidator());
              fRegistry.put("float", new FloatValidator());
              fRegistry.put("double", new DoubleValidator());
              fRegistry.put("timeDuration", new TimeDurationValidator());
              fRegistry.put("timeInstant", new TimeInstantValidator());
              fRegistry.put("binary", new BinaryValidator());
              fRegistry.put("uri", new URIValidator());
              //REVISIT - enable the below
              //fRegistry.put("date", new DateValidator());
              //fRegistry.put("timePeriod", new TimePeriodValidator());
              //fRegistry.put("time", new TimeValidator());
  
  
              DatatypeValidator v = null;
              for (int i = 0; i < integerSubtypeTable.length; i++) {
                  v = new IntegerValidator();
                  facets = new Hashtable();
                  facets.put(integerSubtypeTable[i][1],integerSubtypeTable[i][2]);
                  v.setBasetype(integerValidator);
                  try {
                      v.setFacets(facets);
                  } catch (IllegalFacetException ife) {
                      System.out.println("Internal error initializing registry - Illegal facet: "+integerSubtypeTable[i][0]);
                  } catch (IllegalFacetValueException ifve) {
                      System.out.println("Internal error initializing registry - Illegal facet value: "+integerSubtypeTable[i][0]);
                  } catch (UnknownFacetException ufe) {
                      System.out.println("Internal error initializing registry - Unknown facet: "+integerSubtypeTable[i][0]);
                  }
                  fRegistry.put(integerSubtypeTable[i][0], v);
              }
          }
  
          DatatypeValidator getValidatorFor(String type) {
              return (DatatypeValidator) fRegistry.get(type);
          }
  
          void addValidator(String name, DatatypeValidator v) {
              fRegistry.put(name,v);
          }
      }
  
      //
      //
      //
      final class AttValidatorDATATYPE implements XMLValidator.AttributeValidator {
          public int normalize(int elementType, int attrName, int attValueHandle, int attType, int enumHandle) throws Exception {
              //
              // Normalize attribute based upon attribute type...
              //
              try { // REVISIT - integrate w/ error handling
                  String type = fStringPool.toString(enumHandle);
                  DatatypeValidator v = fDatatypeRegistry.getValidatorFor(type);
                  if (v != null)
                      v.validate(fStringPool.toString(attValueHandle));
                  else
                      reportSchemaError(SchemaMessageProvider.NoValidatorFor,
                                          new Object [] { type });
              } catch (InvalidDatatypeValueException idve) {
                  reportSchemaError(SchemaMessageProvider.IncorrectDatatype,
                                      new Object [] { idve.getMessage() });
              } catch (Exception e) {
                  e.printStackTrace();
                  System.out.println("Internal error in attribute datatype validation");
              }
              return attValueHandle;
          }
      }
      //
      //
      //
      public XMLValidator.AttributeValidator createDatatypeAttributeValidator() {
          return new AttValidatorDATATYPE();
      }
      public XMLContentModel createDatatypeContentModel(int elementIndex) {
          return new DatatypeContentModel(fDatatypeRegistry, fValidator, fStringPool, elementIndex);
      }
  }
  
  
  
  1.1                  xml-xerces/java/src/org/apache/xerces/validators/schema/SchemaParser.java
  
  Index: SchemaParser.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xerces" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 1999, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  
  // TODO - error messages
  
  
  
  package org.apache.xerces.validators.schema;
  
  
  import java.util.Stack;
  import java.util.StringTokenizer;
  
  import org.apache.xerces.framework.XMLAttrList;
  import org.apache.xerces.framework.XMLContentSpec;
  import org.apache.xerces.framework.XMLDocumentHandler;
  import org.apache.xerces.framework.XMLParser;
  import org.apache.xerces.readers.XMLEntityHandler;
  import org.apache.xerces.framework.XMLErrorReporter;
  import org.apache.xerces.utils.StringPool;
  
  
  public class SchemaParser
      extends XMLParser
      implements XMLDocumentHandler, XMLDocumentHandler.DTDHandler {
  
  	
  	private Schema			fSchema;
  	private Schema.Document	fSchemaDocument;
  	private Stack			fComponentStack = new Stack ();
  
  	private boolean			fIgnore				= false;
  	private boolean			fInSimpleType		= false;
  
  
      //
      // Constructors
      //
  
      /** Default constructor. */
      public SchemaParser (Schema schema) {
          initHandlers(true, this, this);
  		fSchema = schema;
      }
  
  
  
      //
      // Public methods
      //
  
  
      //
      // XMLParser methods
      //
  
  
      /** Start document. */
      public void startDocument() throws Exception {
  		System.out.println ("SchemaParser.startDocument\n");
      }
  
      /** End document. */
      public void endDocument() throws Exception {
  		System.out.println ("SchemaParser.endDocument\n");
      }
  
      /** XML declaration. */
      public void xmlDecl(int versionIndex, int encodingIndex, int standaloneIndex) throws Exception {
  		System.out.println ("SchemaParser.xmlDecl\n");
      }
  
  
      /**
       * Report the start of the scope of a namespace declaration.
       */
      public void startNamespaceDeclScope(int prefix, int uri) throws Exception {
  		System.out.println ("SchemaParser.startNamespaceDeclScope\n");
      }
  
      /**
       * Report the end of the scope of a namespace declaration.
       */
      public void endNamespaceDeclScope(int prefix) throws Exception {
  		System.out.println ("SchemaParser.endNamespaceDeclScope\n");
      }
      
  
  	//
  	// The methods we care about!!!
  	//
  
  	/*
  	 * DESCRIPTION:
  	 *
  	 * This handler is called for the start of each element.  it assumes/requires that
  	 * the root of a Schema document must be a <schema> element.  The spec states that
  	 * this need not be the case, but I can see no practical way to not have one in a 
  	 * Schema document.  So, if fSchemaDocument is null (which indicates that we have
  	 * not yet encountered the <schema> element, we won't accept any other element.
  	 *
  	 * Once the <schema> element has been encounteres, startSchema is called, which
  	 * processes the element and created fSchemaDocument.  After this, other valid
  	 * Schema elements are accepted.  Annotations are always possible.  Otherwise, if 
  	 * processing children of a simpleType, all other child elements are processed as
  	 * facets.  Finally, if not an annotation and if not processing children of a 
  	 * simpleType, all other element types are processed.
  	 *
  	 * 3-27-00	watso	First implementation completed.
  	 *
  	 */
  
      public void startElement(int elementType, XMLAttrList attrList, int attrListIndex) throws Exception 
  	{
  		if ( fSchemaDocument == null ) {
  			if ( elementType == fStringPool.addSymbol(Schema.ELT_SCHEMA) ) {
  				startSchema (attrList, attrListIndex);
  			} else {
  				reportGenericSchemaError ( "Invalid root element" );
  			}
  		} else {
  			if ( elementType == fStringPool.addSymbol(Schema.ELT_ANNOTATION) ) {
  				startAnnotation ();
  			} else if ( elementType == fStringPool.addSymbol(Schema.ELT_DOCUMENTATION) ) {
  				startDocumentation ();
  			} else if ( elementType == fStringPool.addSymbol(Schema.ELT_APPINFO) ) {
  				startAppInfo ();
  			} else if ( fInSimpleType ) {
  				startFacet (elementType, attrList, attrListIndex);
  			} else {
  				if ( elementType == fStringPool.addSymbol(Schema.ELT_SIMPLETYPE) ) {
  					startSimpleTypeDef (attrList, attrListIndex);
  				} else if ( elementType == fStringPool.addSymbol(Schema.ELT_COMPLEXTYPE) ) {
  					startComplexTypeDef (attrList, attrListIndex);
  				} else if ( elementType == fStringPool.addSymbol(Schema.ELT_GROUP) ) {
  					startGroupDef (attrList, attrListIndex);
  				} else if ( elementType == fStringPool.addSymbol(Schema.ELT_CHOICE) ) {
  					startChoice (attrList, attrListIndex);
  				} else if ( elementType == fStringPool.addSymbol(Schema.ELT_SEQUENCE) ) {
  					startSeq (attrList, attrListIndex);
  				} else if ( elementType == fStringPool.addSymbol(Schema.ELT_ALL) ) {
  					startAll (attrList, attrListIndex);
  				} else if ( elementType == fStringPool.addSymbol(Schema.ELT_ATTRGROUP) ) {
  					startAttrGroupDef (attrList, attrListIndex);
  				} else if ( elementType == fStringPool.addSymbol(Schema.ELT_ELEMENT) ) {
  					startElementDecl (attrList, attrListIndex);
  				} else if ( elementType == fStringPool.addSymbol(Schema.ELT_ATTRIBUTE) ) { 
  					startAttributeDecl (attrList, attrListIndex);
  				} else if ( elementType == fStringPool.addSymbol(Schema.ELT_NOTATION) ) {
  					startNotationDecl (attrList, attrListIndex);
  				} else {
  					reportGenericSchemaError ( "Invalid element(" + fStringPool.toString (elementType) + ")" );
  				} 
  			}
  		}
  	}
  
  
  	/*
  	 * DESCRIPTION:
  	 *
  	 * startElement should ensure that endElement will only be called once 
  	 * fSchemaDocument has been created.  Annotations are always possible.
  	 * Otherwise, if processing the children of a simpleType, look for either
  	 * the end of the simpleType or process the element as a facet.
  	 *
  	 * Otherwise, process the acceptable elements.
  	 *
  	 * Note: endSchema must set fSchemaDocument to null again to avoid processing
  	 * elements after the </schema> element.
  	 *
  	 * 3-27-00	watso	First implementation completed.
  	 *
  	 */ 
  
      public void endElement(int elementType) throws Exception 
  	{
  	
  		if ( elementType == fStringPool.addSymbol(Schema.ELT_ANNOTATION) ) {
  			endAnnotation ();
  		} else if ( elementType == fStringPool.addSymbol(Schema.ELT_DOCUMENTATION) ) {
  			endDocumentation ();
  		} else if ( elementType == fStringPool.addSymbol(Schema.ELT_APPINFO) ) {
  			endAppInfo ();
  		} else if ( fInSimpleType ) {
  			if ( elementType == fStringPool.addSymbol(Schema.ELT_SIMPLETYPE) ) {
  				endSimpleTypeDef ();
  			} else {
  				endFacet ();
  			}
  		} else {
  			if ( elementType == fStringPool.addSymbol(Schema.ELT_COMPLEXTYPE) ) {
  				endComplexTypeDef ();
  			} else if ( elementType == fStringPool.addSymbol(Schema.ELT_GROUP) ) {
  				endGroupDef ();
  			} else if ( elementType == fStringPool.addSymbol(Schema.ELT_CHOICE) ) {
  				endChoice ();
  			} else if ( elementType == fStringPool.addSymbol(Schema.ELT_SEQUENCE) ) {
  				endSeq ();
  			} else if ( elementType == fStringPool.addSymbol(Schema.ELT_ALL) ) {
  				endAll ();
  			} else if ( elementType == fStringPool.addSymbol(Schema.ELT_ATTRGROUP) ) {
  				endAttrGroupDef ();
  			} else if ( elementType == fStringPool.addSymbol(Schema.ELT_ELEMENT) ) {
  				endElementDecl ();
  			} else if ( elementType == fStringPool.addSymbol(Schema.ELT_ATTRIBUTE) ) { 
  				endAttributeDecl ();
  			} else if ( elementType == fStringPool.addSymbol(Schema.ELT_NOTATION) ) {
  				endNotationDecl ();
  			} else if ( elementType == fStringPool.addSymbol(Schema.ELT_SCHEMA) ) {
  				endSchema ();
  			} else {	
  				reportGenericSchemaError ( "Invalid element (" + fStringPool.toString (elementType) + ")" );
  			}
  		}
      }
  
      /** Start entity reference. */
      public void startEntityReference(int entityName, int entityType, int entityContext) throws Exception {
  		//System.out.println ("SchemaParser.startEntityReference\n");
      }
  
      /** End entity reference. */
      public void endEntityReference(int entityName, int entityType, int entityContext) throws Exception {
  		//System.out.println ("SchemaParser.endEntityReference\n");
      }
  
      /** Start CDATA section. */
      public void startCDATA() throws Exception {
  		System.out.println ("SchemaParser.startCDATA\n");
      }
  
      /** End CDATA section. */
      public void endCDATA() throws Exception {
  		System.out.println ("SchemaParser.endCDATA\n");
      }
  
      /** Not called. */
      public void characters(int dataIndex) throws Exception {
          throw new RuntimeException("PAR017 cannot happen 5\n5");
      }
  
      /** Not called. */
      public void ignorableWhitespace(int dataIndex) throws Exception {
          throw new RuntimeException("PAR017 cannot happen 6\n6");
      }
  
      /** Processing instruction. */
  	/*
      public void processingInstruction(int piTarget, int piData) throws Exception {
  		System.out.println ("SchemaParser.processingInstruction\n");
      }
  	*/
  
      /** Comment. */
  	/*
      public void comment(int dataIndex) throws Exception {
      }
  	*/
  
  
  	// ************************
  	// **** CHARACTER DATA ****
  	// ************************
  
  	/*
  	 *	characters
  	 *
  	 *	Process the character data in an element.
  	 *
  	 */
  
  
  	private static final int	NONE = 0;
  	private static final int	DOCUMENTATION = 1;
  	private static final int	APPINFO = 2;	
  	private static int			fCharacterMode = 0;
  
  
  	/*
  	 * DESCRIPTION:
  	 *
  	 * Character data is only valid in the 'documentation' and 'appinfo' children
  	 * of annotations.
  	 *
  	 * 3-27-00	watso	First implementation completed.
  	 *
  	 */
  
      public void characters (char ch[], int start, int length) throws Exception 
  	{
  		String string = new String (ch, start, length);
  
  		switch (fCharacterMode) {
  		case DOCUMENTATION:
  			{
  			Schema.Annotation annotation = (Schema.Annotation)fComponentStack.peek ();
  			annotation.addDocumentation (string);
  			}
  			break;
  		case APPINFO:
  			{
  			Schema.Annotation annotation = (Schema.Annotation)fComponentStack.peek ();
  			annotation.addAppInfo (string);
  			}
  			break;
  		default:
  			reportGenericSchemaError ("Invalid CDATA");
  		}
      }
  
  
  
      /** Ignorable whitespace. */
      public void ignorableWhitespace(char ch[], int start, int length) throws Exception {
      }
  
  	//
  	// DTDHandler Methods (NOP)
  	//
  
  	public void startDTD (int rootElementType, int publicId, int systemId) throws Exception {}
      public void internalSubset(int internalSubset) throws Exception {}
      public void textDecl(int version, int encoding) throws Exception {}
      public void endDTD() throws Exception {}
      public void elementDecl(int elementType, XMLContentSpec contentSpec) throws Exception {}
      public void attlistDecl(int elementType,int attrName, int attType, String enumString, int attDefaultType, int attDefaultValue) throws Exception {}
      public void internalPEDecl(int entityName, int entityValue) throws Exception {}
      public void externalPEDecl(int entityName, int publicId, int systemId) throws Exception {}
      public void internalEntityDecl(int entityName, int entityValue) throws Exception {}
      public void externalEntityDecl(int entityName, int publicId, int systemId) throws Exception {}
      public void unparsedEntityDecl(int entityName, int publicId, int systemId, int notationName) throws Exception {}
      public void notationDecl(int notationName, int publicId, int systemId) throws Exception {}
      public void processingInstruction(int targetIndex, int dataIndex) throws Exception {}
      public void comment(int dataIndex) throws Exception {}
  
  
  
  	//
  	// SchemaParser Methods - the meat!
  	//
  
  
  	// ***************************
  	// **** STRING CONVERTERS ****
  	// ***************************
  
  
  	/*
  	 * DESCRIPTION
  	 *
  	 * These methods each convert string attribute values to the data representations
  	 * used by the Schema objects.
  	 *
  	 * TODO:	Tweak the values for the 'set' data, e.g. final, derivationSet, blockSet.
  	 *			I'm not sure if these are correct ... need to review latest spec schema.
  	 *
  	 * 3-27-00	watso	First implementation completed.
  	 *
  	 */
  
  
  	private boolean parseBoolean (String booleanString) throws Exception
  	{
  		if ( booleanString.equals("true") ) {
  			return true;
  		} else if ( booleanString.equals("false") ) {
  			return false;
  		} else {
  			reportGenericSchemaError ("Invalid boolean value");
  			return false;
  		}
  	}
  
  	private int parseSimpleDerivedBy (String derivedByString) throws Exception
  	{
  		if ( derivedByString.equals (Schema.VAL_LIST) ) {
  			return Schema.LIST;
  		} else if ( derivedByString.equals (Schema.VAL_RESTRICTION) ) {
  			return Schema.RESTRICTION;
  		} else if ( derivedByString.equals (Schema.VAL_REPRODUCTION) ) {
  			return Schema.REPRODUCTION;
  		} else {
  			reportGenericSchemaError ("Invalid value for 'derivedBy'");
  			return -1;
  		}
  	}
  
  	private int parseComplexDerivedBy (String derivedByString)  throws Exception
  	{
  		if ( derivedByString.equals (Schema.VAL_EXTENSION) ) {
  			return Schema.EXTENSION;
  		} else if ( derivedByString.equals (Schema.VAL_RESTRICTION) ) {
  			return Schema.RESTRICTION;
  		} else if ( derivedByString.equals (Schema.VAL_REPRODUCTION) ) {
  			return Schema.REPRODUCTION;
  		} else {
  			reportGenericSchemaError ( "Invalid value for 'derivedBy'" );
  			return -1;
  		}
  	}
  
  	private int parseSimpleFinal (String finalString) throws Exception
  	{
  		if ( finalString.equals (Schema.VAL_POUNDALL) ) {
  			return Schema.ENUMERATION+Schema.RESTRICTION+Schema.LIST+Schema.REPRODUCTION;
  		} else {
  			int enumerate = 0;
  			int restrict = 0;
  			int list = 0;
  			int reproduce = 0;
  
  			StringTokenizer t = new StringTokenizer (finalString, " ");
  			while (t.hasMoreTokens()) {
  				String token = t.nextToken ();
  
  				if ( token.equals (Schema.VAL_ENUMERATION) ) {
  					if ( enumerate == 0 ) {
  						enumerate = Schema.ENUMERATION;
  					} else {
  						reportGenericSchemaError ("enumeration in set twice");
  					}
  				} else if ( token.equals (Schema.VAL_RESTRICTION) ) {
  					if ( restrict == 0 ) {
  						restrict = Schema.RESTRICTION;
  					} else {
  						reportGenericSchemaError ("restriction in set twice");
  					}
  				} else if ( token.equals (Schema.VAL_LIST) ) {
  					if ( list == 0 ) {
  						list = Schema.LIST;
  					} else {
  						reportGenericSchemaError ("list in set twice");
  					}
  				} else if ( token.equals (Schema.VAL_REPRODUCTION) ) {
  					if ( reproduce == 0 ) {
  						reproduce = Schema.REPRODUCTION;
  					} else {
  						reportGenericSchemaError ("reproduction in set twice");
  					}
  				} else {
  						reportGenericSchemaError (	"Invalid value (" + 
  													finalString +
  													")" );
  				}
  			}
  
  			return enumerate+restrict+list+reproduce;
  		}
  	}
  
  	private int parseComplexContent (String contentString)  throws Exception
  	{
  		if ( contentString.equals (Schema.VAL_EMPTY) ) {
  			return Schema.EMPTY;
  		} else if ( contentString.equals (Schema.VAL_ELEMENTONLY) ) {
  			return Schema.ELEMENT_ONLY;
  		} else if ( contentString.equals (Schema.VAL_TEXTONLY) ) {
  			return Schema.TEXT_ONLY;
  		} else if ( contentString.equals (Schema.VAL_MIXED) ) {
  			return Schema.MIXED;
  		} else {
  			reportGenericSchemaError ( "Invalid value for content" );
  			return -1;
  		}
  	}
  
  	private int parseDerivationSet (String finalString)  throws Exception
  	{
  		if ( finalString.equals ("#all") ) {
  			return Schema.EXTENSION+Schema.RESTRICTION+Schema.REPRODUCTION;
  		} else {
  			int extend = 0;
  			int restrict = 0;
  			int reproduce = 0;
  
  			StringTokenizer t = new StringTokenizer (finalString, " ");
  			while (t.hasMoreTokens()) {
  				String token = t.nextToken ();
  
  				if ( token.equals (Schema.VAL_EXTENSION) ) {
  					if ( extend == 0 ) {
  						extend = Schema.EXTENSION;
  					} else {
  						reportGenericSchemaError ( "extension already in set" );
  					}
  				} else if ( token.equals (Schema.VAL_RESTRICTION) ) {
  					if ( restrict == 0 ) {
  						restrict = Schema.RESTRICTION;
  					} else {
  						reportGenericSchemaError ( "restriction already in set" );
  					}
  				} else if ( token.equals (Schema.VAL_REPRODUCTION) ) {
  					if ( reproduce == 0 ) {
  						reproduce = Schema.REPRODUCTION;
  					} else {
  						reportGenericSchemaError ( "reproduction already in set" );
  					}
  				} else {
  					reportGenericSchemaError ( "Invalid final value (" + finalString + ")" );
  				}
  			}
  
  			return extend+restrict+reproduce;
  		}
  	}
  
  	private int parseBlockSet (String finalString)  throws Exception
  	{
  		if ( finalString.equals ("#all") ) {
  			return Schema.EQUIVCLASS+Schema.EXTENSION+Schema.LIST+Schema.RESTRICTION+Schema.REPRODUCTION;
  		} else {
  			int extend = 0;
  			int restrict = 0;
  			int reproduce = 0;
  
  			StringTokenizer t = new StringTokenizer (finalString, " ");
  			while (t.hasMoreTokens()) {
  				String token = t.nextToken ();
  
  				if ( token.equals (Schema.VAL_EQUIVCLASS) ) {
  					if ( extend == 0 ) {
  						extend = Schema.EQUIVCLASS;
  					} else {
  						reportGenericSchemaError ( "'equivClass' already in set" );
  					}
  				} else if ( token.equals (Schema.VAL_EXTENSION) ) {
  					if ( extend == 0 ) {
  						extend = Schema.EXTENSION;
  					} else {
  						reportGenericSchemaError ( "extension already in set" );
  					}
  				} else if ( token.equals (Schema.VAL_LIST) ) {
  					if ( extend == 0 ) {
  						extend = Schema.LIST;
  					} else {
  						reportGenericSchemaError ( "'list' already in set" );
  					}
  				} else if ( token.equals (Schema.VAL_RESTRICTION) ) {
  					if ( restrict == 0 ) {
  						restrict = Schema.RESTRICTION;
  					} else {
  						reportGenericSchemaError ( "restriction already in set" );
  					}
  				} else if ( token.equals (Schema.VAL_REPRODUCTION) ) {
  					if ( reproduce == 0 ) {
  						reproduce = Schema.REPRODUCTION;
  					} else {
  						reportGenericSchemaError ( "reproduction already in set" );
  					}
  				} else {
  					reportGenericSchemaError ( "Invalid final value (" + finalString + ")" );
  				}
  			}
  
  			return extend+restrict+reproduce;
  		}
  	}
  
  	// *************************
  	// **** SCHEMA DOCUMENT ****
  	// *************************
  
  
  	private void startSchema (XMLAttrList attrList, int attrListIndex) throws Exception
  	{
  		fSchemaDocument = fSchema.createDocument ();
  	}
  
  	private void endSchema () throws Exception
  	{
  		//
  		// TODO: add namespace
  		//
  
  		// Just for testing.
  
  		fSchema.registerDocument (null, fSchemaDocument);
  		fSchemaDocument = null;
  		System.out.print ("\n\n***************** SCHEMA *****************\n\n");
  		System.out.print (fSchema.toString ());
  		System.out.print ("\n\n***************** SCHEMA *****************\n\n");
  	}
  
  
  	// *********************
  	// **** ANNOTATIONS ****
  	// *********************
  
  	/*
  	 * DESCRIPTION:
  	 *
  	 * Each Schema component may have one annotation and it must be the first
  	 * child element of that component.  The Schema document may have multiple
  	 * annotations and they may appear anywhere.  Each annotation may have one
  	 * or more <documentation> and/or <appInfo> children.
  	 *
  	 * 3-27-00	watso	First implementation completed.
  	 *
  	 */
  
  	private void startAnnotation () throws Exception
  	{
  		if ( fSchemaDocument != null ) {
  			Schema.Annotation annotation = fSchemaDocument.createAnnotation ();
  			fComponentStack.push (annotation);
  		} else {
  			reportGenericSchemaError ("Invalid annotation placement");
  		}
  	}
  
  	private void endAnnotation () throws Exception
  	{
  		if ( fSchemaDocument != null ) {
  			Schema.Annotation annotation = (Schema.Annotation)fComponentStack.pop ();
  
  			if ( fComponentStack.size() == 0 ) {
  				fSchemaDocument.addAnnotation (annotation);
  			} else {
  				Schema.AnnotatedComponent annotated = (Schema.AnnotatedComponent)fComponentStack.peek ();
  				annotated.setAnnotation (annotation);
  			}
  		}
  	}	
  
  	private void startDocumentation ()
  	{
  		fCharacterMode = DOCUMENTATION;
  	}
  
  	private void endDocumentation ()
  	{
  		fCharacterMode = NONE;
  	}
  
  	private void startAppInfo ()
  	{
  		fCharacterMode = APPINFO;
  	}
  
  	private void endAppInfo ()
  	{
  		fCharacterMode = NONE;
  	}
  
  
  	// **********************
  	// **** SIMPLE TYPES **** 
  	// **********************
  
  	/*
  	 * DESCRIPTION:
  	 * 
  	 * Create a new simple type def and push on the component stack.  
  	 *
  	 * 3-27-00	watso	First implementation completed.
  	 *
  	 */
  
  
  	//
  	// <simpleType [name={name}] [base={base}] [derivedBy={derivedBy}] [abstract={abstract}] [final={final}]>
  	//
  
  	private void startSimpleTypeDef (XMLAttrList attrList, int attrListIndex) throws Exception
  	{
  		Schema.SimpleTypeDef type = fSchemaDocument.createSimpleTypeDef ();
  
  		for (int i=attrList.getFirstAttr(attrListIndex); i != -1; i = attrList.getNextAttr(i) ) {
  
  			String value = fStringPool.toString (attrList.getAttValue(i));
  
  			if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_NAME) ) {
  				if ( fComponentStack.empty() ) {
  					type.setName (value);
  				} else {
  					reportGenericSchemaError ( "Non-global 'simpleType' cannot have name" );
  				}
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_BASE) ) {
  				type.setBase (value, null);
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_DERIVEDBY) ) {
  				type.setDerivedBy (parseSimpleDerivedBy(value));			
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_ABSTRACT) ) {
  				type.setAbstract (parseBoolean(value));			
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_FINAL) ) {
  				type.setFinal (parseSimpleFinal(value));			
  			} else {
  				reportGenericSchemaError ("Invalid attribute for 'simpleType'");
  			}
  		}
  
  		fComponentStack.push (type);
  		fInSimpleType = true;
  	}
  
  	//
  	// </simpleType>
  	//
  
  	/*
  	 * DESCRIPTION:
  	 *
  	 * Pop the finished simple type off of the component stack.  If the resulting component
  	 * stack is empty then register the simple type as a global type def with the document.
  	 * Otherwise, the next component on the component stack should be something that can have
  	 * a simple type (otherwise an error will result).
  	 *
  	 * 3-27-00	watso	First implementation completed.
  	 *
  	 */
  
  	private void endSimpleTypeDef () throws Exception
  	{
  		fInSimpleType = false;
  
  		Schema.SimpleTypeDef type = (Schema.SimpleTypeDef)fComponentStack.pop ();
  
  		if ( fComponentStack.size() == 0 ) {
  			fSchemaDocument.registerType (type.getName(), type);
  		} else {
  			try {
  				Schema.HasSimpleType component = (Schema.HasSimpleType)fComponentStack.peek ();
  				component.setSimpleType (type);
  			} catch (ClassCastException e) {
  				reportGenericSchemaError ("Invalid use of 'simpleType'");
  			}
  		}
  	}
  
  	//
  	// <{facet} value={value}>
  	//
  
  	// TODO - what about xmlns attributes?
  
  	/*
  	 * DESCRIPTION:
  	 *
  	 * A generic facet adding mechanism to support extended primitive types.  Basically,
  	 * whenever we are in the body of a simple type def, the fInSimpleType flag is set.
  	 * When this is the case, we attempt to process all non-annotations in this method.
  	 * We accept any element name (the facet name) and require there to be a single
  	 * 'value' attribute.  We pass the pair to the enclosing simple type def to process.
  	 *
  	 * 3-27-00	watso	First implementation completed.
  	 *
  	 */
  
  	private void startFacet (int elementType, XMLAttrList attrList, int attrListIndex) throws Exception
  	{
  		// can only have one attribute, and must be "value"
  
  		for (int i=attrList.getFirstAttr(attrListIndex); i != -1; i = attrList.getNextAttr(i) ) {
  			if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_VALUE) ) {
  				try {
  					String name = fStringPool.toString (elementType);
  					String value = fStringPool.toString (attrList.getAttValue(i));
  					Schema.Facet facet = fSchemaDocument.createFacet (name, value);
  					fComponentStack.push (facet);
  				} catch (ClassCastException e) {
  					reportGenericSchemaError ("Unexpected error");
  				}
  			} else {
  				reportGenericSchemaError ("Invalid facet");
  			}
  		}
  	}
  
  	//
  	// </{facet}>
  	//
  
  	private void endFacet ()
  	{
  		Schema.Facet facet = (Schema.Facet)fComponentStack.pop ();
  		Schema.SimpleTypeDef type = (Schema.SimpleTypeDef)fComponentStack.peek ();
  		type.addFacet (facet);
  	}
  
  
  	// ***********************
  	// **** COMPLEX TYPES ****
  	// ***********************
  
  	//
  	// <complexType [name={name}] [content={content}] [base={base}] [derivedBy={derivedBy}]
  	//				[abstract={abstract}] [final={final}] [block={block}]>
  	//
  
  	private void startComplexTypeDef (XMLAttrList attrList, int attrListIndex) throws Exception
  	{
  		Schema.ComplexTypeDef type = fSchemaDocument.createComplexTypeDef ();
  
  		for (int i=attrList.getFirstAttr(attrListIndex); i != -1; i = attrList.getNextAttr(i) ) {
  
  			String value = fStringPool.toString (attrList.getAttValue(i));
  
  			if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_NAME) ) {
  				if ( fComponentStack.empty() ) {
  					type.setName (value);
  				} else {
  					reportGenericSchemaError ("Non-global complexType cannot have name");
  				}
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_CONTENT) ) {
  				type.setContent (parseComplexContent(value));
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_BASE) ) {
  				type.setBase (value, null);
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_DERIVEDBY) ) {
  				type.setDerivedBy (parseComplexDerivedBy(value));			
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_ABSTRACT) ) {
  				type.setAbstract (parseBoolean(value));			
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_FINAL) ) {
  				type.setFinal (parseDerivationSet(value));			
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_BLOCK) ) {
  				type.setBlock (parseDerivationSet(value));			
  			} else {
  				reportGenericSchemaError (	"Invalid attribute (" +
  											fStringPool.toString (attrList.getAttrName(i)) + 
  											")" );
  			}
  		}
  
  		fComponentStack.push (type);
  	}
  
  	//
  	// </complexType>
  	//
  
  	/*
  	 * Pop the finished complex type off of the component stack.  If the resulting component
  	 * stack is empty then register the complex type as a global type def with the document.
  	 * Otherwise, the next component on the component stack should be something that can have
  	 * a complex type (otherwise an error will result).
  	 *
  	 * 3-27-00	watso	First implementation completed.
  	 *
  	 */
  
  	private void endComplexTypeDef () throws Exception
  	{
  		Schema.ComplexTypeDef type = (Schema.ComplexTypeDef)fComponentStack.pop ();
  
  		if ( fComponentStack.size() == 0 ) {
  			fSchemaDocument.registerType (type.getName(), type);
  		} else {
  			try {
  				Schema.HasType component = (Schema.HasType)fComponentStack.peek ();
  				component.setType (type);
  			} catch (ClassCastException e) {
  				reportGenericSchemaError ("Invalid use of 'complexType'");
  			}
  		}
  	}
  
  
  	// ****************
  	// **** GROUPS ****
  	// ****************
  
  	//
  	// <group [name={name}] [ref={ref}] [minOccurs={minOccurs}] [maxOccurs={maxOccurs}]>
  	//
  
  	// TODO: represent minOccurs and maxOccurs as BigDecimal
  	// TODO: use integer datatype class to parse integers
  
  	private void startGroupDef (XMLAttrList attrList, int attrListIndex) throws Exception
  	{
  		String name = null;
  		String ref = null;
  		String minOccurs = null;
  		String maxOccurs = null;
  
  		//
  		// Collect attributes
  		//
  
  		for (int i=attrList.getFirstAttr(attrListIndex); i != -1; i = attrList.getNextAttr(i) ) {
  
  			String value = fStringPool.toString (attrList.getAttValue(i));
  
  			if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_NAME) ) {
  				name = value;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_REF) ) {
  				ref = value;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_MINOCCURS) ) {
  				minOccurs = value;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_MAXOCCURS) ) {
  				maxOccurs = value;
  			} else {
  				reportGenericSchemaError (		"Invalid attribute (" +
  												fStringPool.toString (attrList.getAttrName(i)) +
  												")" );
  			}
  		}
  
  		//
  		// Global group def case
  		//
  
  		if ( fComponentStack.size() == 0 ) {
  			if ( name == null ) {
  				//reportSchemaError (	SchemaMessageProvider.GlobalGroupMustHaveName, null );
  			}
  			if ( ref != null ) {
  				//reportSchemaError (	SchemaMessageProvider.GlobalGroupCannotHaveRef, null );
  			}
  			if ( minOccurs != null ) {
  				//reportSchemaError (	SchemaMessageProvider.InvalidMinOccurs, null );
  			}		
  			if ( maxOccurs != null ) {
  				//reportSchemaError (	SchemaMessageProvider.InvalidMaxOccurs, null );
  			}
  
  			Schema.GroupDef group = fSchemaDocument.createGroupDef ();
  			group.setName (name);
  			fComponentStack.push (group);
  		} 
  		
  		//
  		// Embedded group particle case
  		//
  		
  		else {
  
  			Schema.GroupDef group = null;
  			Schema.GroupParticle particle = fSchemaDocument.createGroupParticle ();
  
  			if ( name != null ) {
  				//reportSchemaError (	SchemaMessageProvider.OnlyGlobalGroupCanHaveName, null );
  			}
  
  			if ( ref == null ) {
  				group = fSchemaDocument.createGroupDef ();
  			}
  
  			//
  			// Set particle minOccurs and maxOccurs
  			//
  
  			if ( minOccurs == null ) {
  				particle.setMinOccurs (1);
  			} else {
  				particle.setMinOccurs (Integer.parseInt(minOccurs));
  			}
  
  			if ( maxOccurs == null ) {
  				particle.setMaxOccurs (1);
  			} else if ( maxOccurs.equals (Schema.VAL_INFINITY) ) {
  				particle.setMaxOccurs (Schema.INFINITY);
  			} else {
  				particle.setMaxOccurs (Integer.parseInt(maxOccurs));
  			}
  
  			fComponentStack.push (particle);
  			fComponentStack.push (group);
  		}
  	}
  
  	//
  	// </group>
  	//
  
  	private void endGroupDef () throws Exception
  	{
  		/*
  		Schema.GroupDef group = (Schema.GroupDef)fComponentStack.pop ();
  
  		if ( group.isNamed() ) {
  			fSchemaDocument.register (group);
  		} else {
  			Schema.ComplexTypeDef type = (Schema.ComplexTypeDef)fComponentStack.peek ();
  			type.appendParticle (group);
  		}
  		*/
  	}
  
  	//
  	// <choice>
  	//
  
  	private void startChoice (XMLAttrList attrList, int attrListIndex)
  	{
  		Schema.GroupDef groupDef = (Schema.GroupDef)fComponentStack.peek();
  		groupDef.setOrder (Schema.CHOICE);
  	}
  
  	//
  	// </choice>
  	//
  
  	private void endChoice () { /* nothing to do */ }
  
  	//
  	// <seq>
  	//
  
  	private void startSeq (XMLAttrList attrList, int attrListIndex)
  	{
  		Schema.GroupDef groupDef = (Schema.GroupDef)fComponentStack.peek();
  		groupDef.setOrder (Schema.SEQUENCE);
  	}
  
  	//
  	// </seq>
  	//
  
  	private void endSeq () { /* nothing to do */ }
  
  	//
  	// <all>
  	//
  
  	private void startAll (XMLAttrList attrList, int attrListIndex)
  	{
  		Schema.GroupDef groupDef = (Schema.GroupDef)fComponentStack.peek();
  		groupDef.setOrder (Schema.ALL);
  	}
  
  	//
  	// </all>
  	//
  
  	private void endAll () { /* nothing to do */ }
  
  
  
  	// **************************
  	// **** ATTRIBUTE GROUPS ****
  	// **************************
  
  	//
  	// <attributeGroup [name=<name> | ref=<ref>]>
  	//
  
  	private void startAttrGroupDef (XMLAttrList attrList, int attrListIndex) throws Exception
  	{
  		String name = null;
  		String ref = null;
  
  		for (int i=attrList.getFirstAttr(attrListIndex); i != -1; i = attrList.getNextAttr(i) ) {
  
  			String value = fStringPool.toString (attrList.getAttValue(i));
  
  			if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_NAME) ) {
  				name = value;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_REF) ) {
  				ref = value;
  			} else {
  				reportGenericSchemaError ( "InvalidAttribute" );
  			}
  		}
  
  		if ( fComponentStack.size() == 0 ) {
  			if ( name != null ) {
  				if ( ref == null ) {
  					Schema.AttributeGroupDef attrGroup = fSchemaDocument.createAttributeGroupDef ();
  					fComponentStack.push (attrGroup);
  				} else {
  					reportGenericSchemaError ("Global def cannot have ref");
  				}
  			} else {
  				reportGenericSchemaError ("Global def must have name");
  			}
  		} else {
  			if ( name == null ) {
  				Schema.AttributeGroupParticle particle = fSchemaDocument.createAttributeGroupParticle ();
  				if ( ref != null ) {
  					// TODO: namespace
  					particle.setAttributeGroupRef (ref, null);
  				}
  			} else {
  				reportGenericSchemaError ("Non-global def cannot have name");
  			}
  		}
  	}
  
  	//
  	// </attributeGroup>
  	//
  
  	private void endAttrGroupDef () throws Exception
  	{
  		if ( fComponentStack.size() == 1 ) {
  			Schema.AttributeGroupDef attrGroupDef = (Schema.AttributeGroupDef)fComponentStack.pop ();
  			fSchemaDocument.registerAttributeGroupDef (attrGroupDef.getName(), attrGroupDef);
  		} else {
  			Schema.AttributeGroupParticle particle = (Schema.AttributeGroupParticle)fComponentStack.pop ();
  			Schema.AParticleHolder holder = (Schema.AParticleHolder)fComponentStack.peek ();
  			holder.add (particle);
  		}	
  	}
  
  
  	// ******************
  	// **** ELEMENTS ****
  	// ******************
  
  	private void startElementDecl (XMLAttrList attrList, int attrListIndex) throws Exception
  	{
  		String name = null;
  		String ref = null;
  		String type = null;
  		String equivClass = null;
  		String minOccurs = null;
  		String maxOccurs = null;
  		String fixedValue = null;
  		String defaultValue = null;
  		String isNullable = null;
  		String isAbstract = null;
  		String finalSet = null;
  		String blockSet = null;
  
  		for (int i=attrList.getFirstAttr(attrListIndex); i != -1; i = attrList.getNextAttr(i) ) {
  
  			String attValue = fStringPool.toString (attrList.getAttValue(i));
  
  			if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_NAME) ) {
  				name = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_REF) ) {
  				ref = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_TYPE) ) {
  				type = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_EQUIVCLASS) ) {
  				equivClass = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_MINOCCURS) ) {
  				minOccurs = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_MAXOCCURS) ) {
  				maxOccurs = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_DEFAULT) ) {
  				defaultValue = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_FIXED) ) {
  				fixedValue = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_NULLABLE) ) {
  				isNullable = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_ABSTRACT) ) {
  				isAbstract = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_FINAL) ) {
  				finalSet = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_BLOCK) ) {
  				blockSet = attValue;
  			} else {
  				reportGenericSchemaError ("Invalid attribute for 'element'");
  			}
  		}
  
  		if ( fComponentStack.size() == 0 ) {
  			if ( name != null && ref == null && minOccurs == null && maxOccurs == null ) {
  				Schema.ElementDecl element = fSchemaDocument.createElementDecl ();
  				element.setName (name);
  				if ( type != null ) element.setType (type, null);
  				if ( equivClass != null ) element.setEquivClass (equivClass, null);
  				if ( isNullable != null ) element.setNullable (parseBoolean(isNullable));
  				if ( isAbstract != null ) element.setAbstract (parseBoolean(isAbstract));
  				if ( defaultValue != null ) element.setDefaultValue (defaultValue);
  				if ( fixedValue != null ) element.setFixedValue (fixedValue);
  				if ( finalSet != null ) element.setFinal (parseDerivationSet(finalSet));
  				if ( blockSet != null ) element.setBlock (parseBlockSet(blockSet));
  				fComponentStack.push (element);
  			} else {
  				reportGenericSchemaError ("Invalid global 'element' declaration");
  			}
  		} else {
  			Schema.ElementParticle particle = fSchemaDocument.createElementParticle ();
  
  			if (equivClass == null && finalSet == null ) {
  				if ( ref != null ) {
  					if ( name == null && type == null ) {
  
  					} else {
  						reportGenericSchemaError ("Invalid 'element' particle");
  					}
  
  				} else {
  					if ( name != null ) {
  						particle.setName (name);
  					} else {
  						reportGenericSchemaError ("Invalid 'element' particle");
  					}
  				}
  
  				if ( isNullable != null ) particle.setNullable (parseBoolean(isNullable));
  				if ( isAbstract != null ) particle.setAbstract (parseBoolean(isAbstract));
  				if ( defaultValue != null ) particle.setDefaultValue (defaultValue);
  				if ( fixedValue != null ) particle.setFixedValue (fixedValue);
  
  			} else {
  				reportGenericSchemaError ("Invalid 'element' particle");
  			}
  
  			fComponentStack.push (particle);
  		}
  	}
  
  	/*
  	 * Description:
  	 *
  	 * The other side of starting an element.  If it's a global element
  	 * decl then it will be the only thing on the component stack by this 
  	 * point.  In this case, remove the element decl from the component
  	 * stack and register it at the global level with the schema document.
  	 *
  	 * Otherwise, an element particle will be on the component stack.
  	 * Remove it and add it to the element particle holder (group def 
  	 * or complex type def) that should be on the stack below.
  	 *
  	 * Errors:
  	 *
  	 * A class cast exception indicatates that something on the component
  	 * stack was not what we exptected it to be.
  	 *
  	 */
  
  	private void endElementDecl () throws Exception
  	{
  		try {
  			if ( fComponentStack.size() == 1 ) {
  
  				// Global element decl
  
  				Schema.ElementDecl element = (Schema.ElementDecl)fComponentStack.pop ();
  				fSchemaDocument.registerElementDecl (element.getName(), element);
  
  			} else {
  
  				// Nested element decl (particle)
  
  				Schema.ElementParticle particle = (Schema.ElementParticle)fComponentStack.pop ();
  				Schema.EParticleHolder holder = (Schema.EParticleHolder)fComponentStack.peek ();
  				holder.add (particle);
  
  			}
  		} catch (ClassCastException e) {
  			reportGenericSchemaError ("Component stack error!");
  		}
  	}
  
  
  	// ********************
  	// **** ATTRIBUTES ****
  	// ********************
  
  	/*
  	 * Description:
  	 *
  	 * An attribute decl can either be a global attribute decl or a an attribute 
  	 * particle that is contained in either a complex type def or an attribute 
  	 * group def.  An attribute particle can either be an attribute decl or a 
  	 * reference to a global attribute decl.
  	 *
  	 * If it's a global attribute decl, we will put an attribute decl on the component
  	 * stack.  Subsequent element processing may lead to adding things to this, e.g.
  	 * an annotation or simple type def, before it is closed.  If it's not global, we
  	 * will put an attribute particle on the component stack.  Things can be added to
  	 * this as well.
  	 *
  	 */
  
  	private void startAttributeDecl (XMLAttrList attrList, int attrListIndex) throws Exception
  	{
  		String name = null;
  		String ref = null;
  		String type = null;
  		String use = null;
  		String value = null;
  
  		for (int i=attrList.getFirstAttr(attrListIndex); i != -1; i = attrList.getNextAttr(i) ) {
  
  			String attValue = fStringPool.toString (attrList.getAttValue(i));
  
  			if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_NAME) ) {
  				name = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_REF) ) {
  				ref = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_TYPE) ) {
  				type = attValue;
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_USE) ) {
  				use = attValue;	
  			} else if ( attrList.getAttrName(i) == fStringPool.addSymbol(Schema.ATT_VALUE) ) {
  				value = attValue;	
  			} else {
  				reportGenericSchemaError ("Invalid attribute for 'attribute'");
  			}
  		}
  
  		if ( fComponentStack.size() == 0 ) {
  			if ( name != null ) {
  				if ( ref == null ) {
  					Schema.AttributeDecl attribute = fSchemaDocument.createAttributeDecl ();
  					// TODO: namespaces
  					if ( type != null ) attribute.setSimpleType (type, null);
  					if ( use != null ) attribute.setUse (parseUse(use));
  					if ( value != null ) attribute.setValue (value);
  					fComponentStack.push (attribute);
  				} else {
  					reportGenericSchemaError ("Global 'attribute' declaration may not have ref");
  				}
  			} else {
  				reportGenericSchemaError ("Global 'attribute' declaration must have name");
  			}
  		} else {
  			Schema.AttributeParticle particle = fSchemaDocument.createAttributeParticle ();
  			if ( ref != null ) particle.setAttributeRef (ref, null);
  			if ( type != null ) particle.setSimpleType (type, null);
  			if ( use != null ) particle.setUse (parseUse(use));
  			if ( value != null ) particle.setValue (value);
  			fComponentStack.push (particle);
  		}
  	}
  
  
  	/*
  	 * Description:
  	 *
  	 * Translate a string value of the "use" attribute to its
  	 * corresponding Schema integer representation.
  	 *
  	 * Errors:
  	 *
  	 * An invalid value for the use attribute.
  	 *
  	 */
  
  	private int parseUse (String useString)  throws Exception
  	{
  		if ( useString.equals (Schema.VAL_OPTIONAL) ) {
  			return Schema.OPTIONAL;
  		} else if ( useString.equals (Schema.VAL_REQUIRED) ) {
  			return Schema.REQUIRED;
  		} else if ( useString.equals (Schema.VAL_DEFAULT) ) {
  			return Schema.DEFAULT;
  		} else if ( useString.equals (Schema.VAL_FIXED) ) {
  			return Schema.FIXED;
  		} else if ( useString.equals (Schema.VAL_PROHIBITED) ) {
  			return Schema.PROHIBITED;
  		} else {
  			reportGenericSchemaError ("Invalid value for 'use'" );
  			return -1;
  		}
  	}
  
  
  	/*
  	 * Description:
  	 *
  	 * The other side of starting an attribute.  If it's a global attribute
  	 * decl then it will be the only thing on the component stack by this 
  	 * point.  In this case, remove the attribute decl from the component
  	 * stack and register it at the global level with the schema document.
  	 *
  	 * Otherwise, an attribute particle will be on the component stack.
  	 * Remove it and add it to the attribute particle holder (attribute 
  	 * group def or complex type def) that should be on the stack below.
  	 *
  	 * Errors:
  	 *
  	 * A class cast exception indicatates that something on the component
  	 * stack was not what we exptected it to be.
  	 *
  	 */
  
  	private void endAttributeDecl () throws Exception
  	{
  		try {
  
  			if ( fComponentStack.size() == 1 ) {
  
  				// Global attribute decl
  
  				Schema.AttributeDecl attribute = (Schema.AttributeDecl)fComponentStack.pop ();
  				fSchemaDocument.registerAttributeDecl (attribute.getName(), attribute);
  
  			} else {
  
  				// Nested attribute decl (particle)
  
  				Schema.AttributeParticle particle = (Schema.AttributeParticle)fComponentStack.pop ();
  				Schema.AParticleHolder holder = (Schema.AParticleHolder)fComponentStack.peek ();
  				holder.add (particle);
  
  			}
  
  		} catch (ClassCastException e) {
  			reportGenericSchemaError ("Component stack error!");
  		}
  	}
  
  
  
  	// *******************
  	// **** NOTATIONS ****
  	// *******************
  
  	private void startNotationDecl (XMLAttrList attrList, int attrListIndex)
  	{
  	}
  
  	private void endNotationDecl ()
  	{
  		//System.out.println ("</notation>\n");
  	}
  
  
  
  	// *************************
  	// **** ERROR REPORTING ****
  	// *************************
  
  	private void reportSchemaError(int major, Object args[]) throws Exception {
      	reportError(	getLocator(),
  						SchemaMessageProvider.SCHEMA_DOMAIN,
  						major,
  						SchemaMessageProvider.MSG_NONE,
  						args,
  						XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR );
  	}
  
  	private void reportGenericSchemaError (String error) throws Exception {
  		reportSchemaError (SchemaMessageProvider.GenericError, new Object[] { error });
  	}
  
  
  } // class SchemaParser