[Zope3-checkins] CVS: Packages/ZConfig - schema.py:1.1.2.1 SchemaParser.py:NONE
Fred L. Drake, Jr.
fred@zope.com
Tue, 10 Dec 2002 16:50:08 -0500
Update of /cvs-repository/Packages/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv20623
Added Files:
Tag: zconfig-schema-devel-branch
schema.py
Removed Files:
Tag: zconfig-schema-devel-branch
SchemaParser.py
Log Message:
Rename "SchemaParser" module to "schema".
=== Added File Packages/ZConfig/schema.py ===
"""Parser for ZConfig schemas."""
import xml.sax
import ZConfig
from ZConfig import datatypes
from ZConfig import info
default_value_type = datatypes.get("str")
default_key_type = datatypes.get("basic-key")
default_name_type = default_key_type
_identifier = datatypes.get("identifier").convert
class SchemaParser(xml.sax.ContentHandler):
_cdata_tags = "description", "metadefault", "example", "default"
_handled_tags = "schema", "key", "section", "sectiongroup"
def __init__(self):
self._cdata = None
self._locator = None
self._prefixes = []
self._schema = None
self._stack = []
self._sections = []
def parseStream(self, stream):
xml.sax.parse(stream, self)
return self._schema
# SAX 2 ContentHandler methods
def setDocumentLocator(self, locator):
self._locator = locator
def startElement(self, name, attrs):
attrs = dict(attrs)
if name == "schema":
if self._schema:
self.doSchemaError("schema element improperly nested")
self.start_schema(attrs)
elif name in self._handled_tags:
if not self._schema:
self.doSchemaError(name + " element outside of schema")
getattr(self, "start_" + name)(attrs)
elif name in self._cdata_tags:
if not self._schema:
self.doSchemaError(name + " element outside of schema")
if self._cdata is not None:
self.doSchemaError(name + " element improperly nested")
self._cdata = []
else:
self.doSchemaError("Unknown tag " + name)
def characters(self, data):
if self._cdata is not None:
self._cdata.append(data)
elif data.strip():
self.doSchemaError("unexpected non-blank character data: "
+ data.strip())
def endElement(self, name):
if name in self._handled_tags:
getattr(self, "end_" + name)()
else:
data = ''.join(self._cdata).strip()
self._cdata = None
if name == "default":
# value for a key
self._stack[-1].adddefault(data)
else:
setattr(self._stack[-1], name, data)
def endDocument(self):
if not self._schema:
self.doSchemaError("no schema found")
# schema loading logic
def get_classname(self, name):
if name.startswith(".") and self._prefixes:
return self._prefixes[-1] + name
else:
return name
def push_prefix(self, attrs):
name = attrs.get("prefix")
self._prefixes.append(self.get_classname(name or ""))
def start_schema(self, attrs):
self._prefixes.append(attrs.get("prefix", ""))
handler = attrs.get("handler")
if handler:
handler = self.get_classname(handler)
if attrs.has_key("keytype"):
keytype = datatypes.get(attrs["keytype"])
else:
keytype = default_key_type
self._schema = info.SchemaInfo(handler, keytype)
self._sections = [self._schema]
self._stack = [self._schema]
def end_schema(self):
del self._prefixes[-1]
assert not self._prefixes
del self._sections[-1]
assert not self._sections
def start_section(self, attrs):
self.push_prefix(attrs)
type = attrs.get("type")
if not type:
self.doSchemaError("section does not specify type")
if attrs.has_key("keytype"):
keytype = datatypes.get(attrs["keytype"])
else:
keytype = default_key_type
if attrs.has_key("nametype"):
nametype = datatypes.get(attrs["nametype"])
else:
nametype = default_name_type
maxOccurs, minOccurs, handler = self.get_common_info(attrs)
any, names, attribute = self.get_names_info(attrs, nametype)
if self._stack:
parent = self._stack[-1]
else:
parent = self._schema
section = info.SectionInfo(None, None, minOccurs, maxOccurs, handler,
attribute, keytype, names, nametype)
if any:
parent.addsection(None, section)
else:
for n in names:
parent.addsection(n, section)
self._stack.append(section)
self._sections.append(section)
def end_section(self):
del self._prefixes[-1]
del self._sections[-1]
self._stack.pop().finish()
def start_sectiongroup(self, attrs):
self.push_prefix(attrs)
name = attrs.get("name")
if not name:
self.doSchemaError("section group must be named")
raise NotImpementedError("sectiongroup support not yet implemented")
def end_sectiongroup(self):
del self._prefixes[-1]
def start_key(self, attrs):
name = attrs.get("name")
if not name:
self.doSchemaError("key name may not be omitted or empty")
# run the keytype converter to make sure this is a valid key
name = self._stack[-1].keytype.convert(name)
datatype = datatypes.get(attrs.get("type"))
maxOccurs, minOccurs, handler = self.get_common_info(attrs)
attribute = attrs.get("attribute")
if attribute:
attribute = _identifier(attribute)
else:
attribute = _identifier(name.replace("-", "_"))
key = info.KeyInfo(name, datatype, minOccurs, maxOccurs, handler,
attribute)
self._sections[-1].addkey(key)
self._stack.append(key)
def end_key(self):
self._stack.pop().finish()
def get_common_info(self, attrs):
maxOccurs = attrs.get("maxOccurs")
if maxOccurs is not None:
if maxOccurs == "unbounded":
maxOccurs = info.Unbounded
else:
maxOccurs = int(maxOccurs)
else:
maxOccurs = 1
minOccurs = attrs.get("minOccurs")
if minOccurs:
minOccurs = int(minOccurs)
if minOccurs > maxOccurs:
self.doSchemaError("minOccurs cannot be more than maxOccurs")
else:
minOccurs = None
handler = attrs.get("handler")
if handler:
handler = self.get_classname(handler)
return maxOccurs, minOccurs, handler
def get_names_info(self, attrs, nametype):
if not attrs.get("names"):
self.doSchemaError("allowed section names must be specified")
anyname = None
names = []
s = attrs["names"]
if s in ("*", "+"):
aname = attrs.get("attribute")
if not aname:
self.doSchemaError(
"container attribute must be specified when using"
" '*' or '+' for section names")
return s, (), _identifier(aname)
for s in s.split("|"):
s = s.strip()
if not s:
self.doSchemaError("empty section name not allowed")
if s in ("*", "+"):
self.doSchemaError(
"'+' and '*' cannot be combined with other names")
else:
s = nametype.convert(s)
if s in ("*", "+"):
self.doSchemaError("nametypes may not convert to"
" '*' or '+'")
names.append(s)
if attrs.has_key("attribute"):
if len(names) > 1:
self.doSchemaError(
"cannot give target attribute name with"
" multiple named sections")
aname = _identifier(attrs["attribute"])
else:
aname = None
return None, tuple(names), aname
def doSchemaError(self, message):
raise ZConfig.ConfigurationError(message)
=== Removed File Packages/ZConfig/SchemaParser.py ===