⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmldtd.py

📁 Python Development Environment (Python IDE plugin for Eclipse). Features editor, code completion, re
💻 PY
📖 第 1 页 / 共 2 页
字号:
"""
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 + -