[Zope3-checkins] CVS: Zope/lib/python/ZConfig - SchemaParser.py:1.1.2.16
Fred L. Drake, Jr.
fred@zope.com
Thu, 5 Dec 2002 15:13:58 -0500
Update of /cvs-repository/Zope/lib/python/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv19436
Modified Files:
Tag: chrism-install-branch
SchemaParser.py
Log Message:
Convert to use SAX 2 instead of xml.parsers.expat, so we're not bound
to a specific parser.
=== Zope/lib/python/ZConfig/SchemaParser.py 1.1.2.15 => 1.1.2.16 ===
--- Zope/lib/python/ZConfig/SchemaParser.py:1.1.2.15 Sat Nov 30 00:54:16 2002
+++ Zope/lib/python/ZConfig/SchemaParser.py Thu Dec 5 15:13:57 2002
@@ -18,6 +18,7 @@
"""
import types
+import xml.sax
from Common import *
from Config import Configuration
@@ -32,48 +33,14 @@
nodefault = []
-class SchemaParser:
+class SchemaParser(xml.sax.ContentHandler):
- handler_names = [
- "StartElementHandler",
- "EndElementHandler",
- "ProcessingInstructionHandler",
- "CharacterDataHandler",
- "UnparsedEntityDeclHandler",
- "NotationDeclHandler",
- "StartNamespaceDeclHandler",
- "EndNamespaceDeclHandler",
- "CommentHandler",
- "StartCdataSectionHandler",
- "EndCdataSectionHandler",
- "DefaultHandler",
- "DefaultHandlerExpand",
- "NotStandaloneHandler",
- "ExternalEntityRefHandler",
- "XmlDeclHandler",
- "StartDoctypeDeclHandler",
- "EndDoctypeDeclHandler",
- "ElementDeclHandler",
- "AttlistDeclHandler"
- ]
-
- def __init__(self, encoding='ascii'):
- self.parser = p = self.createParser(encoding)
- for name in self.handler_names:
- method = getattr(self, name, None)
- if method is not None:
- setattr(p, name, method)
- self.cdata_tags = ('description', 'metadefault', 'example')
-
- def createParser(self, encoding=None):
- global XMLParseError
- from xml.parsers import expat
- XMLParseError = expat.ExpatError
- parser = expat.ParserCreate(encoding, ' ')
- parser.returns_unicode = False
- if hasattr(parser, 'buffer_text'):
- parser.buffer_text = True
- return parser
+ _cdata_tags = 'description', 'metadefault', 'example'
+ _current_cdata_attr = None
+ _locator = None
+
+ def __init__(self):
+ self._schema = None
def __call__(self, f, context, print_classes=False):
self._stack = []
@@ -87,48 +54,62 @@
self.parseStream(f)
def parseFile(self, filename):
- self.parseStream(open(filename))
+ xml.sax.parse(open(filename, 'rU'), self)
def parseString(self, s):
- self.parser.Parse(s, 1)
+ xml.sax.parseString(s, self)
def parseStream(self, stream):
- self.parser.ParseFile(stream)
+ xml.sax.parse(stream, self)
+
+ # SAX 2 ContentHandler methods
- def parseFragment(self, s, end=0):
- self.parser.Parse(s, end)
+ def setDocumentLocator(self, locator):
+ self._locator = locator
- def StartElementHandler(self, name, attrs):
+ def startElement(self, name, attrs):
+ attrs = dict(attrs)
if name == SCHEMA_TYPE:
- return self.handleSchema(attrs)
+ self.handleSchema(attrs)
elif name == KEY_TYPE:
- return self.handleKey(attrs)
+ if not self._schema:
+ self.doSchemaError(`name` + " element outside of schema")
+ self.handleKey(attrs)
elif name == SECTION_TYPE:
- return self.handleSection(attrs)
- elif name in self.cdata_tags:
- return self.handleCdata(name)
- msg = "Unknown tag %s" % name
- self.doSchemaError(msg)
+ if not self._schema:
+ self.doSchemaError(`name` + " element outside of schema")
+ self.handleSection(attrs)
+ elif name in self._cdata_tags:
+ if not self._schema:
+ self.doSchemaError(`name` + " element outside of schema")
+ self.handleCdata(name)
+ else:
+ self.doSchemaError("Unknown tag %s" % name)
- def CharacterDataHandler(self, data):
+ def characters(self, data):
data = data.strip()
if not data:
return
attr = self.getCurrentCdata()
if attr is None:
- msg = 'cdata only valid within %s tags' % (self.cdata_tags,)
- self.doSchemaError(msg)
+ self.doSchemaError('#pcdata only valid within %s tags'
+ % `self._cdata_tags`[1:-1])
setattr(self._stack[-1], attr, data)
- def EndElementHandler(self, name):
- if name in self.cdata_tags:
- self.current_cdata_attr = None
+ def endElement(self, name):
+ if name in self._cdata_tags:
+ self._current_cdata_attr = None
return
- if name == SCHEMA_TYPE:
- self.checkClasses()
- self.context.setSchema(self._stack[0])
self._stack.pop()
+ def endDocument(self):
+ if not self._schema:
+ self.doSchemaError("no schema found")
+ self.checkClasses()
+ self.context.setSchema(self._schema)
+
+ # schema handling logic
+
def checkClasses(self):
items = self._seen_classes.items()
items.sort()
@@ -142,7 +123,7 @@
self.doSchemaError('Class loading failed for: %s' % ', '.join(l))
def getCurrentCdata(self):
- return getattr(self, 'current_cdata_attr', None)
+ return self._current_cdata_attr
def handleCdata(self, name):
if not self._stack:
@@ -152,14 +133,14 @@
if current:
msg = 'Cannot place %s attribute in %s' % (name, current)
self.doSchemaError(msg)
- self.current_cdata_attr = name
+ self._current_cdata_attr = name
def getClass(self, name):
if name.startswith('.'):
name = self._prefix + name
if self._seen_classes.get(name, missing) is missing:
try:
- klass = importer(name)
+ klass = importer(str(name))
except ImportError:
klass = ConfigMissing
self._seen_classes[name] = klass
@@ -208,11 +189,12 @@
config = Klass(type, name, self.context, None)
except Exception, e:
self.doSchemaError(str(e))
+ self._schema = config
self._stack.append(config)
def handleKey(self, attrs):
if self.getCurrentCdata():
- msg = 'cannot nest key in %s' % self.cdata_tags
+ msg = 'cannot nest key in ' + `self._cdata_tags`
self.doSchemaError(msg)
if not self._stack:
msg = '"key" tag valid only within "schema" tag and subordinates'
@@ -251,7 +233,7 @@
def handleSection(self, attrs):
if self.getCurrentCdata():
- msg = 'cannot nest section in %s' % self.cdata_tags
+ msg = 'cannot nest section in ' + 'self._cdata_tags'
self.doSchemaError(msg)
if not self._stack:
msg = ('"section" tag valid only within "schema" tag '
@@ -286,8 +268,12 @@
self._stack.append(config)
def doSchemaError(self, msg):
- raise SchemaError(msg, self.parser.ErrorLineNumber,
- self.parser.ErrorColumnNumber)
+ if self._locator is None:
+ colno = lineno = None
+ else:
+ colno = self._locator.getColumnNumber()
+ lineno = self._locator.getLineNumber()
+ raise SchemaError(msg, lineno, colno)
class SchemaError(Exception):
def __init__(self, msg, line, col):
@@ -296,7 +282,11 @@
self.col = col
def __str__(self):
- return "%s at line %s, column %s" % (self.msg, self.line, self.col)
+ if self.line is not None:
+ pos = " at line %d, column %s" % (self.line, self.col)
+ else:
+ pos = " (unknown position)"
+ return self.msg + pos
class SchemaConfiguration(Configuration):
resolved = missing
@@ -709,7 +699,8 @@
def importer(name):
components = name.split('.')
start = components[0]
- package = __import__(start, globals(), globals())
+ g = globals()
+ package = __import__(start, g, g)
modulenames = [start]
for component in components[1:]:
modulenames.append(component)
@@ -717,7 +708,7 @@
package = getattr(package, component)
except AttributeError:
name = '.'.join(modulenames)
- package = __import__(name, globals(), globals(), component)
+ package = __import__(name, g, g, component)
return package
if __name__ == '__main__':