📄 xmldtd.py
字号:
"""
These are the DTD-aware classes of xmlproc. They provide both the
DTD event consumers for the DTD parser as well as the objects that
store DTD information for retrieval by clients (including the
validating parser).
$Id$
"""
import types
from xmlutils import *
from xmlapp import *
# ==============================
# WFC-DTD
# ==============================
class WFCDTD(DTDConsumer):
"DTD-representing class for the WFC parser."
def __init__(self,parser):
DTDConsumer.__init__(self,parser)
self.dtd_listener=DTDConsumer(parser)
self.reset()
def reset(self):
"Clears all DTD information."
self.gen_ents={}
self.param_ents={}
self.elems={}
self.attrinfo={}
self.used_notations={} # Notations used by NOTATION attrs
# Adding predefined entities
for name in predef_ents.keys():
self.new_general_entity(name,predef_ents[name])
def set_dtd_listener(self,listener):
"Registers an object that listens for DTD parse events."
self.dtd_listener=listener
def resolve_pe(self,name):
"""Returns the entitiy object associated with this parameter entity
name. Throws KeyError if the entity is not declared."""
return self.param_ents[name]
def resolve_ge(self,name):
"""Returns the entitiy object associated with this general entity
name. Throws KeyError if the entity is not declared."""
return self.gen_ents[name]
def get_general_entities(self):
"""Returns the names of all declared general entities."""
return self.gen_ents.keys()
def get_parameter_entities(self):
"Returns the names of all declared parameter entities."
return self.param_ents.keys()
def get_elem(self,name):
"""Returns the declaration of this element. Throws KeyError if the
element does not exist."""
return self.elems[name]
def get_elements(self):
"Returns a list of all declared element names."
return self.elems.keys()
def get_notation(self,name):
"""Returns the declaration of the notation. Throws KeyError if the
notation does not exist."""
raise KeyError(name)
def get_notations(self):
"""Returns the names of all declared notations."""
return []
def get_root_elem(self,name):
"""Returns the name of the declared root element, or None if none
were declared."""
return None
# --- Shortcut information for validation
def dtd_end(self):
"Stores shortcut information."
self.attrinfo={}
for elem in self.elems.values():
self.attrinfo[elem.get_name()]=(elem.get_default_attributes(),
elem.get_fixed_attributes())
self.dtd_listener.dtd_end()
def get_element_info(self,name):
return self.attrinfo[name]
# --- Parse events
def new_attribute(self,elem,attr,a_type,a_decl,a_def):
"Receives the declaration of a new attribute."
self.dtd_listener.new_attribute(elem,attr,a_type,a_decl,a_def)
if not self.elems.has_key(elem):
self.elems[elem]=ElementTypeAny(elem) # Adding dummy
self.elems[elem].add_attr(attr,a_type,a_decl,a_def,self.parser)
# --- Echoing DTD parse events
def dtd_start(self):
self.dtd_listener.dtd_start()
# dtd_end is implemented in WFCDTD, no need to repeat here
def handle_comment(self, contents):
self.dtd_listener.handle_comment(contents)
def handle_pi(self, target, data):
self.dtd_listener.handle_pi(target, data)
def new_general_entity(self,name,val):
if self.gen_ents.has_key(name):
## FIXME: May warn
return # Keep first decl
ent=InternalEntity(name,val)
self.gen_ents[name]=ent
self.dtd_listener.new_general_entity(name,val)
def new_parameter_entity(self,name,val):
if self.param_ents.has_key(name):
## FIXME: May warn
return # Keep first decl
ent=InternalEntity(name,val)
self.param_ents[name]=ent
self.dtd_listener.new_parameter_entity(name,val)
def new_external_entity(self,ent_name,pubid,sysid,ndata):
if self.gen_ents.has_key(ent_name):
## FIXME: May warn
return # Keep first decl
if ndata!="" and hasattr(self,"notations"):
if not self.notations.has_key(ndata):
self.used_notations[ndata]=(ent_name,2023)
ent=ExternalEntity(ent_name,pubid,sysid,ndata)
self.gen_ents[ent_name]=ent
self.dtd_listener.new_external_entity(ent_name,pubid,sysid,ndata)
def new_external_pe(self,name,pubid,sysid):
if self.param_ents.has_key(name):
## FIXME: May warn
return # Keep first decl
ent=ExternalEntity(name,pubid,sysid,"")
self.param_ents[name]=ent
self.dtd_listener.new_external_pe(name,pubid,sysid)
def new_comment(self,contents):
self.dtd_listener.new_comment(contents)
def new_pi(self,target,rem):
self.dtd_listener.new_pi(target,rem)
def new_notation(self,name,pubid,sysid):
self.dtd_listener.new_notation(name,pubid,sysid)
def new_element_type(self,elem_name,elem_cont):
self.dtd_listener.new_element_type(elem_name,elem_cont)
# ==============================
# DTD consumer for the validating parser
# ==============================
class CompleteDTD(WFCDTD):
"Complete DTD handler for the validating parser."
def __init__(self,parser):
WFCDTD.__init__(self,parser)
def reset(self):
"Clears all DTD information."
WFCDTD.reset(self)
self.notations={}
self.attlists={} # Attribute lists of elements not yet declared
self.root_elem=None
self.cmhash={}
def get_root_elem(self):
"Returns the name of the declared root element."
return self.root_elem
def get_notation(self,name):
"""Returns the declaration of the notation. Throws KeyError if the
notation does not exist."""
return self.notations[name]
def get_notations(self):
"""Returns the names of all declared notations."""
return self.notations.keys()
# --- DTD parse events
def dtd_end(self):
WFCDTD.dtd_end(self)
self.cmhash={}
for elem in self.attlists.keys():
self.parser.report_error(1006,elem)
self.attlists={} # Not needed any more, can free this memory
for notation in self.used_notations.keys():
try:
self.get_notation(notation)
except KeyError,e:
self.parser.report_error(2022,(self.used_notations[notation],
notation))
self.used_notations={} # Not needed, save memory
def new_notation(self,name,pubid,sysid):
self.notations[name]=(pubid,sysid)
self.dtd_listener.new_notation(name,pubid,sysid)
def new_element_type(self,elem_name,elem_cont):
if self.elems.has_key(elem_name):
self.parser.report_error(2012,elem_name)
return # Keeping first declaration
if elem_cont=="EMPTY":
elem_cont=("",[],"")
self.elems[elem_name]=ElementType(elem_name,make_empty_model(),
elem_cont)
elif elem_cont=="ANY":
elem_cont=None
self.elems[elem_name]=ElementTypeAny(elem_name)
else:
model=make_model(self.cmhash,elem_cont,self.parser)
self.elems[elem_name]=ElementType(elem_name,model,elem_cont)
if self.attlists.has_key(elem_name):
for (attr,a_type,a_decl,a_def) in self.attlists[elem_name]:
self.elems[elem_name].add_attr(attr,a_type,a_decl,a_def,\
self.parser)
del self.attlists[elem_name]
self.dtd_listener.new_element_type(elem_name,elem_cont)
def new_attribute(self,elem,attr,a_type,a_decl,a_def):
"Receives the declaration of a new attribute."
self.dtd_listener.new_attribute(elem,attr,a_type,a_decl,a_def)
try:
self.elems[elem].add_attr(attr,a_type,a_decl,a_def,self.parser)
except KeyError,e:
try:
self.attlists[elem].append((attr,a_type,a_decl,a_def))
except KeyError,e:
self.attlists[elem]=[(attr,a_type,a_decl,a_def)]
# ==============================
# Represents an XML element type
# ==============================
class ElementType:
"Represents an element type."
def __init__(self,name,compiled,original):
self.name=name
self.attrhash={}
self.attrlist=[]
self.content_model=compiled
self.content_model_structure=original
def get_name(self):
"Returns the name of the element type."
return self.name
def get_attr_list(self):
"""Returns a list of the declared attribute names in the order the
attributes were declared."""
return self.attrlist
def get_attr(self,name):
"Returns the attribute or throws a KeyError if it's not declared."
return self.attrhash[name]
def add_attr(self,attr,a_type,a_decl,a_def,parser):
"Adds a new attribute to the element."
if self.attrhash.has_key(attr):
parser.report_error(1007,attr)
return # Keep first declaration
self.attrlist.append(attr)
if a_type=="ID":
for attr_name in self.attrhash.keys():
if self.attrhash[attr_name].type=="ID":
parser.report_error(2013)
if a_decl!="#REQUIRED" and a_decl!="#IMPLIED":
parser.report_error(2014)
elif type(a_type)==types.TupleType and a_type[0]=="NOTATION":
for notation in a_type[1]:
parser.dtd.used_notations[notation]=attr
self.attrhash[attr]=Attribute(attr,a_type,a_decl,a_def,parser)
if a_def!=None:
self.attrhash[attr].validate(self.attrhash[attr].default,parser)
def get_start_state(self):
"Return the start state of this content model."
return self.content_model["start"]
def final_state(self,state):
"True if 'state' is a final state."
return self.content_model["final"] & state
def next_state(self,state,elem_name):
"""Returns the next state of the content model from the given one
when elem_name is encountered. Character data is represented as
'#PCDATA'. If 0 is returned the element is not allowed here or if
the state is unknown."""
try:
return self.content_model[state][elem_name]
except KeyError:
return 0
def get_valid_elements(self,state):
"""Returns a list of the valid elements in the given state, or the
empty list if none are valid (or if the state is unknown). If the
content model is ANY, the empty list is returned."""
if self.content_model==None: # that is, any
return [] # any better ideas?
try:
return self.content_model[state].keys()
except KeyError:
return []
def get_content_model(self):
"""Returns the element content model in (sep,cont,mod) format, where
cont is a list of (name,mod) and (sep,cont,mod) tuples. ANY content
models are represented as None, and EMPTYs as ("",[],"")."""
return self.content_model_structure
# --- Methods used to create shortcut validation information
def get_default_attributes(self):
defs={}
for attr in self.attrhash.values():
if attr.get_default()!=None:
defs[attr.get_name()]=attr.get_default()
return defs
def get_fixed_attributes(self):
fixed={}
for attr in self.attrhash.values():
if attr.get_decl()=="#FIXED":
fixed[attr.get_name()]=attr.get_default()
return fixed
# --- Element types with ANY content
class ElementTypeAny(ElementType):
def __init__(self,name):
ElementType.__init__(self,name,None,None)
def get_start_state(self):
return 1
def final_state(self,state):
return 1
def next_state(self,state,elem_name):
return 1
# ==============================
# Attribute
# ==============================
class Attribute:
"Represents a declared attribute."
def __init__(self,name,attrtype,decl,default,parser):
self.name=name
self.type=attrtype
self.decl=decl
# Normalize the default value before setting it
if default!=None and self.type!="CDATA":
self.default=string.join(string.split(default))
else:
self.default=default
# Handling code for special attribute xml:space
if name=="xml:space":
if type(self.type)==types.StringType:
parser.report_error(2015)
return
if len(self.type)!=2:
error=1
else:
if (self.type[0]=="default" and self.type[1]=="preserve") or \
(self.type[1]=="default" and self.type[0]=="preserve"):
error=0
else:
error=1
if error: parser.report_error(2016)
def validate(self,value,parser):
"Validates given value for correctness."
if type(self.type)!=types.StringType:
for val in self.type:
if val==value: return
parser.report_error(2017,(value,self.name))
elif self.type=="CDATA":
return
elif self.type=="ID" or self.type=="IDREF" or self.type=="ENTITIY":
if not matches(reg_name,value):
parser.report_error(2018,self.name)
elif self.type=="NMTOKEN":
if not matches(reg_nmtoken,value):
parser.report_error(2019,self.name)
elif self.type=="NMTOKENS":
if not matches(reg_nmtokens,value):
parser.report_error(2020,self.name)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -