diff --git a/src/xercesc/internal/DGXMLScanner.cpp b/src/xercesc/internal/DGXMLScanner.cpp
index fb3fabbc38895e2dc2bf0bca49d47cb5e086f510..6d3933a2832e4d91afc5d68e3b1f37f23bdff1cc 100644
--- a/src/xercesc/internal/DGXMLScanner.cpp
+++ b/src/xercesc/internal/DGXMLScanner.cpp
@@ -93,6 +93,7 @@ DGXMLScanner::DGXMLScanner(XMLValidator* const valToAdopt
     , fAttrNSList(0)
     , fDTDValidator(0)
     , fDTDGrammar(0)
+    , fDTDElemNonDeclPool(0)
 {
     try
     {
@@ -128,6 +129,7 @@ DGXMLScanner::DGXMLScanner( XMLDocumentHandler* const docHandler
     , fAttrNSList(0)
     , fDTDValidator(0)
     , fDTDGrammar(0)
+    , fDTDElemNonDeclPool(0)
 {
     try
     {	
@@ -778,11 +780,20 @@ void DGXMLScanner::scanDocTypeDecl()
         , fEmptyNamespaceId
         , DTDElementDecl::Any
         , fGrammarPoolMemoryManager
-    );
-
+    ); 
     rootDecl->setCreateReason(DTDElementDecl::AsRootElem);
     rootDecl->setExternalElemDeclaration(true);
-    ((DTDGrammar*)fGrammar)->setRootElemId(fGrammar->putElemDecl(rootDecl));
+    if(!fUseCachedGrammar) 
+    {
+        // this will break getRootElemId on DTDGrammar when
+        // cached grammars are in use, but 
+        // why would one use this anyway???
+        ((DTDGrammar*)fGrammar)->setRootElemId(fGrammar->putElemDecl(rootDecl));
+    } else 
+    {
+        // put this in the undeclared pool so it gets deleted...
+        rootDecl->setId(fDTDElemNonDeclPool->put((DTDElementDecl*)rootDecl));
+    }
 
     // Skip any spaces after the name
     fReaderMgr.skipPastSpaces();
@@ -930,6 +941,10 @@ void DGXMLScanner::scanDocTypeDecl()
                 fDTDGrammar = (DTDGrammar*) grammar;
                 fGrammar = fDTDGrammar;
                 fValidator->setGrammar(fGrammar);
+                // we *cannot* identify the root element on 
+                // cached grammars; else we risk breaking multithreaded
+                // applications.  - NG
+                /*******
                 rootDecl = (DTDElementDecl*) fGrammar->getElemDecl(fEmptyNamespaceId, 0, bbRootName.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
 
                 if (rootDecl)
@@ -946,6 +961,7 @@ void DGXMLScanner::scanDocTypeDecl()
                     rootDecl->setExternalElemDeclaration(true);
                     ((DTDGrammar*)fGrammar)->setRootElemId(fGrammar->putElemDecl(rootDecl));
                 }
+                *********/
 
                 return;
             }
@@ -1032,18 +1048,34 @@ bool DGXMLScanner::scanStartTag(bool& gotData)
     //  this can only be called if we are doing a DTD style validator and that
     //  he will only look at the QName.
     //
-    //  We tell him to fault in a decl if he does not find one.
+    //  We *do not* tell him to fault in a decl if he does not find one - NG.
     bool wasAdded = false;
-    const XMLCh* qnameRawBuf = fQNameBuf.getRawBuffer();
-    XMLElementDecl* elemDecl = fGrammar->findOrAddElemDecl
+    const XMLCh* qnameRawBuf = fQNameBuf.getRawBuffer(); 
+
+    XMLElementDecl* elemDecl = fGrammar->getElemDecl
     (
         fEmptyNamespaceId
         , 0
-        , 0
         , qnameRawBuf
         , Grammar::TOP_LEVEL_SCOPE
-        , wasAdded
     );
+    // look in the undeclared pool:
+    if(!elemDecl) 
+    {
+        elemDecl = fDTDElemNonDeclPool->getByKey(qnameRawBuf);
+    }
+    if(!elemDecl) 
+    {
+        wasAdded = true;
+        elemDecl = new (fMemoryManager) DTDElementDecl 
+        (
+            qnameRawBuf
+            , fEmptyNamespaceId
+            , DTDElementDecl::Any
+            , fMemoryManager
+        );
+        elemDecl->setId(fDTDElemNonDeclPool->put((DTDElementDecl*)elemDecl));
+    }
 
     if (fValidate) {
 
@@ -1802,12 +1834,14 @@ void DGXMLScanner::commonInit()
     //  Create the Validator and init them
     fDTDValidator = new (fMemoryManager) DTDValidator();
     initValidator(fDTDValidator);
+    fDTDElemNonDeclPool = new (fMemoryManager) NameIdPool<DTDElementDecl>(29, 128, fMemoryManager);
 }
 
 void DGXMLScanner::cleanUp()
 {
     delete fAttrNSList;
     delete fDTDValidator;
+    delete fDTDElemNonDeclPool;
 }
 
 
diff --git a/src/xercesc/internal/DGXMLScanner.hpp b/src/xercesc/internal/DGXMLScanner.hpp
index a13dd56e7b7981cf3fa60fcfc874eab124d938ca..c7b63df027d92e4551cc0fa1c8c5510baea3789f 100644
--- a/src/xercesc/internal/DGXMLScanner.hpp
+++ b/src/xercesc/internal/DGXMLScanner.hpp
@@ -56,6 +56,9 @@
 
 /*
  * $Log$
+ * Revision 1.9  2003/09/22 19:51:41  neilg
+ * scanners should maintain their own pools of undeclared elements, rather than requiring grammars to do this.  This makes grammar objects stateless with regard to validation.
+ *
  * Revision 1.8  2003/07/24 09:19:09  gareth
  * Patch for bug  #20530 - Attributes which have the same expanded name are not considered duplicates. Patch by cargilld.
  *
@@ -90,10 +93,12 @@
 #include <xercesc/internal/XMLScanner.hpp>
 #include <xercesc/internal/ElemStack.hpp>
 #include <xercesc/util/ValueVectorOf.hpp>
+#include <xercesc/util/NameIdPool.hpp>
 #include <xercesc/validators/common/Grammar.hpp>
 
 XERCES_CPP_NAMESPACE_BEGIN
 
+class DTDElementDecl;
 class DTDGrammar;
 class DTDValidator;
 
@@ -230,34 +235,20 @@ private :
     //  fDTDValidator
     //      The DTD validator instance.
     //
-    //  fSchemaValidator
-    //      The Schema validator instance.
-    //
-    //  fSeeXsi
-    //      This flag indicates a schema has been seen.
-    //
     //  fElemState
     //  fElemStateSize
     //      Stores an element next state from DFA content model - used for
     //      wildcard validation
     //
-    //  fMatcherStack
-    //      Stack of active XPath matchers for identity constraints. All
-    //      active XPath matchers are notified of startElement, characters
-    //      and endElement callbacks in order to perform their matches.
-    //
-    //  fValueStoreCache
-    //      Cache of value stores for identity constraint fields.
-    //
-    //  fFieldActivator
-    //      Activates fields within a certain scope when a selector matches
-    //      its xpath.
+    // fDTDElemNonDeclPool
+    //     registry of "faulted-in" DTD element decls
     //
     // -----------------------------------------------------------------------
     ElemStack                   fElemStack;
     ValueVectorOf<XMLAttr*>*    fAttrNSList;
     DTDValidator*               fDTDValidator;
     DTDGrammar*                 fDTDGrammar;
+    NameIdPool<DTDElementDecl>* fDTDElemNonDeclPool;
 };
 
 inline const XMLCh* DGXMLScanner::getName() const
diff --git a/src/xercesc/internal/IGXMLScanner.cpp b/src/xercesc/internal/IGXMLScanner.cpp
index ae88ddedccfb50671e5e5477d0539c6f417843e4..e18c88cdf5ae1be74e9439a7036e89db079e0279 100644
--- a/src/xercesc/internal/IGXMLScanner.cpp
+++ b/src/xercesc/internal/IGXMLScanner.cpp
@@ -106,6 +106,8 @@ IGXMLScanner::IGXMLScanner( XMLValidator* const  valToAdopt
     , fMatcherStack(0)
     , fValueStoreCache(0)
     , fFieldActivator(0)
+    , fDTDElemNonDeclPool(0)
+    , fSchemaElemNonDeclPool(0)
 {
     try
     {
@@ -143,6 +145,8 @@ IGXMLScanner::IGXMLScanner( XMLDocumentHandler* const docHandler
     , fMatcherStack(0)
     , fValueStoreCache(0)
     , fFieldActivator(0)
+    , fDTDElemNonDeclPool(0)
+    , fSchemaElemNonDeclPool(0)
 {
     try
     {	
@@ -521,6 +525,9 @@ void IGXMLScanner::commonInit()
 
     // Create schemaLocation pair info
     fLocationPairs = new (fMemoryManager) ValueVectorOf<XMLCh*>(8, fMemoryManager);
+    // create pools for undeclared elements
+    fDTDElemNonDeclPool = new (fMemoryManager) NameIdPool<DTDElementDecl>(29, 128, fMemoryManager);
+    fSchemaElemNonDeclPool = new (fMemoryManager) RefHash3KeysIdPool<SchemaElementDecl>(29, true, 128, fMemoryManager);
 }
 
 void IGXMLScanner::cleanUp()
@@ -533,6 +540,8 @@ void IGXMLScanner::cleanUp()
     delete fMatcherStack;
     delete fValueStoreCache;
     delete fLocationPairs;
+    delete fDTDElemNonDeclPool;
+    delete fSchemaElemNonDeclPool;
 }
 
 // ---------------------------------------------------------------------------
@@ -1187,11 +1196,20 @@ void IGXMLScanner::scanDocTypeDecl()
         , fEmptyNamespaceId
         , DTDElementDecl::Any
         , fGrammarPoolMemoryManager
-    );
-
+    ); 
     rootDecl->setCreateReason(DTDElementDecl::AsRootElem);
     rootDecl->setExternalElemDeclaration(true);
-    ((DTDGrammar*)fGrammar)->setRootElemId(fGrammar->putElemDecl(rootDecl));
+    if(!fUseCachedGrammar) 
+    {
+        // this will break getRootElemId on DTDGrammar when
+        // cached grammars are in use, but 
+        // why would one use this anyway???
+        ((DTDGrammar*)fGrammar)->setRootElemId(fGrammar->putElemDecl(rootDecl));
+    } else
+    {
+        // attach this to the undeclared element pool so that it gets deleted
+        rootDecl->setId(fDTDElemNonDeclPool->put((DTDElementDecl*)rootDecl));
+    }
 
     // Skip any spaces after the name
     fReaderMgr.skipPastSpaces();
@@ -1339,6 +1357,8 @@ void IGXMLScanner::scanDocTypeDecl()
                 fDTDGrammar = (DTDGrammar*) grammar;
                 fGrammar = fDTDGrammar;
                 fValidator->setGrammar(fGrammar);
+                // should not be modifying cached grammars!
+                /********
                 rootDecl = (DTDElementDecl*) fGrammar->getElemDecl(fEmptyNamespaceId, 0, bbRootName.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
 
                 if (rootDecl)
@@ -1355,6 +1375,7 @@ void IGXMLScanner::scanDocTypeDecl()
                     rootDecl->setExternalElemDeclaration(true);
                     ((DTDGrammar*)fGrammar)->setRootElemId(fGrammar->putElemDecl(rootDecl));
                 }
+                ********/
 
                 return;
             }
@@ -1439,16 +1460,36 @@ bool IGXMLScanner::scanStartTag(bool& gotData)
     //  he will only look at the QName.
     //
     //  We tell him to fault in a decl if he does not find one.
+    //  Actually, we *don't* tell him to fault in a decl if he does not find one- NG
     bool wasAdded = false;
-    XMLElementDecl* elemDecl = fGrammar->findOrAddElemDecl
+    const XMLCh *rawQName = fQNameBuf.getRawBuffer();
+    XMLElementDecl* elemDecl = fGrammar->getElemDecl
     (
         fEmptyNamespaceId
         , 0
-        , 0
-        , fQNameBuf.getRawBuffer()
+        , rawQName
         , Grammar::TOP_LEVEL_SCOPE
-        , wasAdded
     );
+    // look for it in the undeclared pool:
+    if(!elemDecl) 
+    {
+        elemDecl = fDTDElemNonDeclPool->getByKey(rawQName);
+    }
+    if(!elemDecl) 
+    {
+        // we're assuming this must be a DTD element.  DTD's can be
+        // used with or without namespaces, but schemas cannot be used without
+        // namespaces.
+        wasAdded = true;
+        elemDecl = new (fMemoryManager) DTDElementDecl 
+        (
+            rawQName
+            , fEmptyNamespaceId
+            , DTDElementDecl::Any
+            , fMemoryManager
+        );
+        elemDecl->setId(fDTDElemNonDeclPool->put((DTDElementDecl*)elemDecl));
+    }
 
     //  We do something different here according to whether we found the
     //  element or not.
@@ -2047,13 +2088,16 @@ bool IGXMLScanner::scanStartTagNS(bool& gotData)
     //  this element.
     XMLElementDecl* elemDecl = 0;
     if (fGrammarType == Grammar::DTDGrammarType) {
+        const XMLCh *rawQName = fQNameBuf.getRawBuffer();
         elemDecl = fGrammar->getElemDecl
         (
             fEmptyNamespaceId
             , 0
-            , fQNameBuf.getRawBuffer()
+            , rawQName
             , Grammar::TOP_LEVEL_SCOPE
         );
+        // may have not been declared:
+        elemDecl = fDTDElemNonDeclPool->getByKey(rawQName);
         if (elemDecl) {
             if (elemDecl->hasAttDefs()) {
                 XMLAttDefList& attDefList = elemDecl->getAttDefList();
@@ -2110,16 +2154,31 @@ bool IGXMLScanner::scanStartTagNS(bool& gotData)
     const XMLCh* original_uriStr = fGrammar->getTargetNamespace();
     unsigned orgGrammarUri = fURIStringPool->getId(original_uriStr);
 
+    // REVISIT:  since all this code only really
+    // makes sense for schemas, why can DTD validation theoretically pass 
+    // through it?  - NG
     if (uriId != fEmptyNamespaceId) {
 
         // Check in current grammar before switching if necessary
+        const XMLCh *rawQName = fQNameBuf.getRawBuffer();
         elemDecl = fGrammar->getElemDecl
         (
           uriId
           , nameRawBuf
-          , qnameRawBuf
+          , rawQName
           , currentScope
         );
+        // may have not been declared; must look everywhere:
+        if (!elemDecl)
+            if(fGrammarType == Grammar::DTDGrammarType) 
+            {
+                // should never occur in practice
+                elemDecl = fDTDElemNonDeclPool->getByKey(rawQName);
+            }
+            else if (fGrammarType == Grammar::SchemaGrammarType) 
+            {
+                elemDecl = fSchemaElemNonDeclPool->getByKey(nameRawBuf, uriId, currentScope);
+            }
 
         if (!elemDecl && (orgGrammarUri != uriId)) {
             // not found, switch to the specified grammar
@@ -2156,6 +2215,12 @@ bool IGXMLScanner::scanStartTagNS(bool& gotData)
                            , Grammar::TOP_LEVEL_SCOPE
                        );
 
+            if(!elemDecl) 
+            {
+                // look in the list of undeclared elements, as would have been done
+                // before we made grammars stateless:
+                elemDecl = fSchemaElemNonDeclPool->getByKey(nameRawBuf, uriId, Grammar::TOP_LEVEL_SCOPE);
+            }
             if(!elemDecl) {
                 // still not found in specified uri
                 // try emptyNamesapce see if element should be un-qualified.
@@ -2185,12 +2250,29 @@ bool IGXMLScanner::scanStartTagNS(bool& gotData)
             // still not found, fault this in and issue error later
             // switch back to original grammar first
             switchGrammar(original_uriStr);
-            elemDecl = fGrammar->putElemDecl(uriId
-                        , nameRawBuf
-                        , fPrefixBuf.getRawBuffer()
-                        , qnameRawBuf
-                        , currentScope
-                        , true);
+            if(fGrammarType == Grammar::DTDGrammarType) 
+            {
+                elemDecl = new (fMemoryManager) DTDElementDecl
+                (
+                    qnameRawBuf
+                    , uriId
+                    , DTDElementDecl::Any
+                    , fMemoryManager
+                );
+                elemDecl->setId(fDTDElemNonDeclPool->put((DTDElementDecl*)elemDecl));
+            } else if (fGrammarType == Grammar::SchemaGrammarType) 
+            {
+                elemDecl = new (fMemoryManager) SchemaElementDecl
+                (
+                    fPrefixBuf.getRawBuffer()
+                    , nameRawBuf
+                    , uriId
+                    , SchemaElementDecl::Any
+                    , Grammar::TOP_LEVEL_SCOPE
+                    , fMemoryManager
+                );
+                elemDecl->setId(fSchemaElemNonDeclPool->put((void*)elemDecl->getBaseName(), uriId, currentScope, (SchemaElementDecl*)elemDecl));
+            }
             wasAdded = true;
         }
     }
@@ -2200,7 +2282,7 @@ bool IGXMLScanner::scanStartTagNS(bool& gotData)
         //thus it is either a non-qualified element defined in current targetNS
         //or an element that is defined in the globalNS
 
-        //try unqualifed first
+        //try unqualified first
         elemDecl = fGrammar->getElemDecl
                    (
                       uriId
@@ -2209,6 +2291,19 @@ bool IGXMLScanner::scanStartTagNS(bool& gotData)
                     , currentScope
                     );
 
+        // may have not been declared; must look everywhere:
+        if(!elemDecl)
+            if (fGrammarType == Grammar::DTDGrammarType) 
+            {
+                // should never happen in practice?
+                elemDecl = fDTDElemNonDeclPool->getByKey(qnameRawBuf);
+            }
+            else if (fGrammarType == Grammar::SchemaGrammarType) 
+            {
+                // look in the list of undeclared elements, as would have been done
+                // before we made grammars stateless:
+                elemDecl = fSchemaElemNonDeclPool->getByKey(nameRawBuf, uriId, currentScope);
+            }
         if (!elemDecl && orgGrammarUri != fEmptyNamespaceId) {
             //not found, switch grammar and try globalNS
             bool errorCondition = !switchGrammar(XMLUni::fgZeroLenString) && fValidate;
@@ -2242,16 +2337,20 @@ bool IGXMLScanner::scanStartTagNS(bool& gotData)
                            , qnameRawBuf
                            , Grammar::TOP_LEVEL_SCOPE
                        );
+            if(!elemDecl)
+            {
+                // look in the list of undeclared elements, as would have been done
+                // before we made grammars stateless:
+                elemDecl = fSchemaElemNonDeclPool->getByKey(nameRawBuf, uriId, Grammar::TOP_LEVEL_SCOPE);
+            }
 
             if (!elemDecl && orgGrammarUri != fEmptyNamespaceId) {
                 // still Not found in specified uri
                 // go to original Grammar again to see if element needs to be fully qualified.
-                const XMLCh* uriStr = getURIText(orgGrammarUri);
                 bool errorCondition = !switchGrammar(original_uriStr) && fValidate;
-                if (errorCondition && !laxThisOne)
-
                 if (errorCondition && !laxThisOne)
                 {
+                    const XMLCh* uriStr = getURIText(orgGrammarUri);
                     fValidator->emitError
                     (
                         XMLValid::GrammarNotFound
@@ -2269,7 +2368,6 @@ bool IGXMLScanner::scanStartTagNS(bool& gotData)
                                , qnameRawBuf
                                , currentScope
                            );
-
                 if (elemDecl && elemDecl->getCreateReason() != XMLElementDecl::JustFaultIn && fValidate) {
                     fValidator->emitError
                     (
@@ -2285,12 +2383,29 @@ bool IGXMLScanner::scanStartTagNS(bool& gotData)
             // still not found, fault this in and issue error later
             // switch back to original grammar first
             switchGrammar(original_uriStr);
-            elemDecl = fGrammar->putElemDecl(uriId
-                        , nameRawBuf
-                        , fPrefixBuf.getRawBuffer()
-                        , qnameRawBuf
-                        , currentScope
-                        , true);
+            if(fGrammarType == Grammar::DTDGrammarType) 
+            {
+                elemDecl = new (fMemoryManager) DTDElementDecl
+                (
+                    qnameRawBuf
+                    , uriId
+                    , DTDElementDecl::Any
+                    , fMemoryManager
+                );
+                elemDecl->setId(fDTDElemNonDeclPool->put((DTDElementDecl*)elemDecl));
+            } else if (fGrammarType == Grammar::SchemaGrammarType) 
+            {
+                elemDecl = new (fMemoryManager) SchemaElementDecl
+                (
+                    fPrefixBuf.getRawBuffer()
+                    , nameRawBuf
+                    , uriId
+                    , SchemaElementDecl::Any
+                    , Grammar::TOP_LEVEL_SCOPE
+                    , fMemoryManager
+                );
+                elemDecl->setId(fSchemaElemNonDeclPool->put((void*)elemDecl->getBaseName(), uriId, currentScope, (SchemaElementDecl*)elemDecl));
+            }
             wasAdded = true;
         }
     }
@@ -2881,6 +2996,8 @@ Grammar* IGXMLScanner::loadDTDGrammar(const InputSource& src,
 
     // Clear out the id reference list
     fIDRefList->removeAll();
+    // and clear out the darned undeclared DTD element pool...
+    fDTDElemNonDeclPool->removeAll();
 
     if (toCache) {
 
diff --git a/src/xercesc/internal/IGXMLScanner.hpp b/src/xercesc/internal/IGXMLScanner.hpp
index 0c9f66e9572c80955d832cd092d8d463235dcef3..d7c8b453d7d6904c68788149c315e086a324d2f7 100644
--- a/src/xercesc/internal/IGXMLScanner.hpp
+++ b/src/xercesc/internal/IGXMLScanner.hpp
@@ -56,6 +56,9 @@
 
 /*
  * $Log$
+ * Revision 1.10  2003/09/22 19:51:41  neilg
+ * scanners should maintain their own pools of undeclared elements, rather than requiring grammars to do this.  This makes grammar objects stateless with regard to validation.
+ *
  * Revision 1.9  2003/08/14 02:56:41  knoaman
  * Code refactoring to improve performance of validation.
  *
@@ -93,11 +96,14 @@
 #include <xercesc/internal/XMLScanner.hpp>
 #include <xercesc/internal/ElemStack.hpp>
 #include <xercesc/util/KVStringPair.hpp>
+#include <xercesc/util/NameIdPool.hpp>
+#include <xercesc/util/RefHash3KeysIdPool.hpp>
 #include <xercesc/validators/common/Grammar.hpp>
 #include <xercesc/validators/schema/SchemaElementDecl.hpp>
 
 XERCES_CPP_NAMESPACE_BEGIN
 
+class DTDElementDecl;
 class DTDGrammar;
 class DTDValidator;
 class SchemaValidator;
@@ -316,6 +322,10 @@ private :
     //  fFieldActivator
     //      Activates fields within a certain scope when a selector matches
     //      its xpath.
+    // fDTDElemNonDeclPool
+    //      registry of "faulted-in" DTD element decls
+    // fSchemaElemNonDeclPool
+    //      registry for elements without decls in the grammar
     //
     // -----------------------------------------------------------------------
     bool                        fSeeXsi;
@@ -332,6 +342,8 @@ private :
     ValueStoreCache*            fValueStoreCache;
     FieldActivator*             fFieldActivator;
     ValueVectorOf<XMLCh*>*      fLocationPairs;
+    NameIdPool<DTDElementDecl>* fDTDElemNonDeclPool;
+    RefHash3KeysIdPool<SchemaElementDecl>* fSchemaElemNonDeclPool;
 };
 
 inline const XMLCh* IGXMLScanner::getName() const
diff --git a/src/xercesc/internal/SGXMLScanner.cpp b/src/xercesc/internal/SGXMLScanner.cpp
index 5967c47cde2c0ef7fdd7571c081985275b9cb2ab..401c644cce0e1cb439279399c3edf65a4986ad24 100644
--- a/src/xercesc/internal/SGXMLScanner.cpp
+++ b/src/xercesc/internal/SGXMLScanner.cpp
@@ -106,6 +106,7 @@ SGXMLScanner::SGXMLScanner( XMLValidator* const valToAdopt
     , fMatcherStack(0)
     , fValueStoreCache(0)
     , fFieldActivator(0)
+    , fElemNonDeclPool(0)
 {
     try
     {
@@ -148,6 +149,7 @@ SGXMLScanner::SGXMLScanner( XMLDocumentHandler* const docHandler
     , fMatcherStack(0)
     , fValueStoreCache(0)
     , fFieldActivator(0)
+    , fElemNonDeclPool(0)
 {
     try
     {	
@@ -1205,7 +1207,12 @@ bool SGXMLScanner::scanStartTag(bool& gotData)
           , qnameRawBuf
           , currentScope
         );
-
+        if(!elemDecl) 
+        {
+            // look in the list of undeclared elements, as would have been done
+            // before we made grammars stateless:
+            elemDecl = fElemNonDeclPool->getByKey(nameRawBuf, uriId, currentScope);
+        }
         if (!elemDecl && (orgGrammarUri != uriId)) {
             // not found, switch to the specified grammar
             const XMLCh* uriStr = getURIText(uriId);
@@ -1240,7 +1247,12 @@ bool SGXMLScanner::scanStartTag(bool& gotData)
                            , qnameRawBuf
                            , Grammar::TOP_LEVEL_SCOPE
                        );
-
+            if(!elemDecl) 
+            {
+                // look in the list of undeclared elements, as would have been done
+                // before we made grammars stateless:
+                elemDecl = fElemNonDeclPool->getByKey(nameRawBuf, uriId, Grammar::TOP_LEVEL_SCOPE);
+            }
             if(!elemDecl) {
                 // still not found in specified uri
                 // try emptyNamesapce see if element should be un-qualified.
@@ -1250,8 +1262,7 @@ bool SGXMLScanner::scanStartTag(bool& gotData)
                                , nameRawBuf
                                , qnameRawBuf
                                , currentScope
-                           );
-
+                           ); 
                 bool errorCondition = elemDecl && elemDecl->getCreateReason() != XMLElementDecl::JustFaultIn;
                 if (errorCondition && fValidate) {
                     fValidator->emitError
@@ -1271,12 +1282,16 @@ bool SGXMLScanner::scanStartTag(bool& gotData)
             // still not found, fault this in and issue error later
             // switch back to original grammar first
             switchGrammar(original_uriStr);
-            elemDecl = fGrammar->putElemDecl(uriId
-                        , nameRawBuf
-                        , fPrefixBuf.getRawBuffer()
-                        , qnameRawBuf
-                        , currentScope
-                        , true);
+            elemDecl = new (fMemoryManager) SchemaElementDecl
+            (
+                fPrefixBuf.getRawBuffer()
+                , nameRawBuf
+                , uriId
+                , SchemaElementDecl::Any
+                , Grammar::TOP_LEVEL_SCOPE
+                , fMemoryManager
+            );
+            elemDecl->setId(fElemNonDeclPool->put((void*)elemDecl->getBaseName(), uriId, currentScope, (SchemaElementDecl*)elemDecl));
             wasAdded = true;
         }
     }
@@ -1294,7 +1309,12 @@ bool SGXMLScanner::scanStartTag(bool& gotData)
                     , qnameRawBuf
                     , currentScope
                     );
-
+        if(!elemDecl)
+        {
+            // look in the list of undeclared elements, as would have been done
+            // before we made grammars stateless:
+            elemDecl = fElemNonDeclPool->getByKey(nameRawBuf, uriId, currentScope);
+        }
         if (!elemDecl && orgGrammarUri != fEmptyNamespaceId) {
             //not found, switch grammar and try globalNS
             bool errorCondition = !switchGrammar(XMLUni::fgZeroLenString) && fValidate;
@@ -1329,7 +1349,12 @@ bool SGXMLScanner::scanStartTag(bool& gotData)
                            , qnameRawBuf
                            , Grammar::TOP_LEVEL_SCOPE
                        );
-
+            if(!elemDecl)
+            {
+                // look in the list of undeclared elements, as would have been done
+                // before we made grammars stateless:
+                elemDecl = fElemNonDeclPool->getByKey(nameRawBuf, uriId, Grammar::TOP_LEVEL_SCOPE);
+            }
             if (!elemDecl && orgGrammarUri != fEmptyNamespaceId) {
                 // still Not found in specified uri
                 // go to original Grammar again to see if element needs to be fully qualified.
@@ -1354,7 +1379,6 @@ bool SGXMLScanner::scanStartTag(bool& gotData)
                                , qnameRawBuf
                                , currentScope
                            );
-
                 if (elemDecl && elemDecl->getCreateReason() != XMLElementDecl::JustFaultIn && fValidate) {
                     fValidator->emitError
                     (
@@ -1370,14 +1394,17 @@ bool SGXMLScanner::scanStartTag(bool& gotData)
             // still not found, fault this in and issue error later
             // switch back to original grammar first
             switchGrammar(original_uriStr);
-            elemDecl = fGrammar->putElemDecl(uriId
-                        , nameRawBuf
-                        , fPrefixBuf.getRawBuffer()
-                        , qnameRawBuf
-                        , currentScope
-                        , true);
+            elemDecl = new (fMemoryManager) SchemaElementDecl
+            (
+                fPrefixBuf.getRawBuffer()
+                , nameRawBuf
+                , uriId
+                , SchemaElementDecl::Any
+                , Grammar::TOP_LEVEL_SCOPE
+                , fMemoryManager
+            );
+            elemDecl->setId(fElemNonDeclPool->put((void*)elemDecl->getBaseName(), uriId, currentScope, (SchemaElementDecl*)elemDecl));
             wasAdded = true;
-
         }
     }
 
@@ -1578,7 +1605,7 @@ bool SGXMLScanner::scanStartTag(bool& gotData)
             , false
             , isRoot
         );
-    }
+    } // may be where we output something...
 
     //  If empty, validate content right now if we are validating and then
     //  pop the element stack top. Else, we have to update the current stack
@@ -1902,6 +1929,7 @@ void SGXMLScanner::commonInit()
     fEntityTable->put((void*) XMLUni::fgGT, chCloseAngle);
     fEntityTable->put((void*) XMLUni::fgQuot, chDoubleQuote);
     fEntityTable->put((void*) XMLUni::fgApos, chSingleQuote);
+    fElemNonDeclPool = new (fMemoryManager) RefHash3KeysIdPool<SchemaElementDecl>(29, true, 128, fMemoryManager);
 }
 
 void SGXMLScanner::cleanUp()
@@ -1914,6 +1942,7 @@ void SGXMLScanner::cleanUp()
     delete fFieldActivator;
     delete fMatcherStack;
     delete fValueStoreCache;
+    delete fElemNonDeclPool;
 }
 
 void SGXMLScanner::resizeElemState() {
diff --git a/src/xercesc/internal/SGXMLScanner.hpp b/src/xercesc/internal/SGXMLScanner.hpp
index 5c5679892e77810614b69e266fec39a56d5f3717..88306791c82ca8b163927bf302dae5195dc9d5c5 100644
--- a/src/xercesc/internal/SGXMLScanner.hpp
+++ b/src/xercesc/internal/SGXMLScanner.hpp
@@ -56,6 +56,9 @@
 
 /*
  * $Log$
+ * Revision 1.9  2003/09/22 19:51:41  neilg
+ * scanners should maintain their own pools of undeclared elements, rather than requiring grammars to do this.  This makes grammar objects stateless with regard to validation.
+ *
  * Revision 1.8  2003/07/10 19:47:23  peiyongz
  * Stateless Grammar: Initialize scanner with grammarResolver,
  *                                creating grammar through grammarPool
@@ -91,13 +94,14 @@
 #include <xercesc/internal/ElemStack.hpp>
 #include <xercesc/util/KVStringPair.hpp>
 #include <xercesc/util/ValueHashTableOf.hpp>
+#include <xercesc/util/RefHash3KeysIdPool.hpp>
 #include <xercesc/validators/common/Grammar.hpp>
 #include <xercesc/validators/schema/SchemaElementDecl.hpp>
 
 XERCES_CPP_NAMESPACE_BEGIN
 
-class SchemaValidator;
 class SchemaGrammar;
+class SchemaValidator;
 class ValueStoreCache;
 class XPathMatcherStack;
 class FieldActivator;
@@ -306,6 +310,8 @@ private :
     //  fFieldActivator
     //      Activates fields within a certain scope when a selector matches
     //      its xpath.
+    // fElemNonDeclPool
+    //      registry for elements without decls in the grammar
     //
     // -----------------------------------------------------------------------
     bool                        fSeeXsi;
@@ -321,6 +327,7 @@ private :
     XPathMatcherStack*          fMatcherStack;
     ValueStoreCache*            fValueStoreCache;
     FieldActivator*             fFieldActivator;
+    RefHash3KeysIdPool<SchemaElementDecl>* fElemNonDeclPool;
 };
 
 inline const XMLCh* SGXMLScanner::getName() const