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

📄 xmlmarshaller.py

📁 Wxpython Implemented on Windows CE, Source code
💻 PY
📖 第 1 页 / 共 4 页
字号:
            
class NsElement(object):
    def __init__(self):
        self.nsMap = {}
        self.targetNS = None
        self.defaultNS = None
        self.prefix = None

    def __str__(self):
        if self.prefix == None:
            strVal = 'prefix = None; '
        else:
            strVal = 'prefix = "%s"; ' % (self.prefix)
        if self.targetNS == None:
            strVal += 'targetNS = None; '
        else:
            strVal += 'targetNS = "%s"; ' % (self.targetNS)
        if self.defaultNS == None:
            strVal += 'defaultNS = None; '
        else:
            strVal += 'defaultNS = "%s"; ' % (self.defaultNS)
        if len(self.nsMap) == 0:
            strVal += 'nsMap = None; '
        else:
            strVal += 'nsMap = {'
            for ik, iv in self.nsMap.iteritems():
                strVal += '%s=%s; ' % (ik,iv)
            strVal += '}'
        return strVal
               
    def setKnownTypes(self, masterKnownTypes, masterKnownNamespaces, parentNSE):
        # if we're a nested element, extend our parent element's mapping
        if parentNSE != None:
            self.knownTypes = parentNSE.knownTypes.copy()
            # but if we have a different default namespace, replace the parent's default mappings
            if (self.defaultNS != None) and (parentNSE.defaultNS != self.defaultNS):
                newKT = self.knownTypes.copy()
                for tag in newKT:
                    if tag.find(':') < 0:
                        del self.knownTypes[tag]
            newMap = parentNSE.nsMap.copy()
            if self.nsMap != {}:
                for k, v in self.nsMap.iteritems():
                    newMap[k] = v
            self.nsMap = newMap
        else:
            self.knownTypes = {}
        reversedKNS = {}
        # TODO: instead of starting with the knownNamespaces, start with the "xmlms" mappings
        # for this element. Then we'd only process the namespaces and tags we need to.
        # But for now, this works.
        for long, short in masterKnownNamespaces.iteritems():
            reversedKNS[short] = long
        mapLongs = self.nsMap.values()
        for tag, mapClass in masterKnownTypes.iteritems():
            i = tag.rfind(':')
            if i >= 0:                                      # e.g. "wsdl:description"
                knownTagShort = tag[:i]                     # "wsdl"
                knownTagName = tag[i+1:]                    # "description"
                knownTagLong  = reversedKNS[knownTagShort]  # e.g. "http://schemas.xmlsoap.org/wsdl"
                if (knownTagLong in mapLongs):
                    for mShort, mLong in self.nsMap.iteritems():
                        if mLong == knownTagLong:
                            actualShort = mShort  # e.g. "ws"
                            actualTag = '%s:%s' % (actualShort, knownTagName)
                            self.knownTypes[actualTag] = mapClass
                            break
                if self.defaultNS == knownTagLong:
                    self.knownTypes[knownTagName] = mapClass
            else:                                           # e.g. "ItemSearchRequest"
                self.knownTypes[tag] = mapClass

    def expandQName(self, eName, attrName, attrValue):
        bigValue = attrValue
        i = attrValue.rfind(':')
        if (i < 0):
            if self.defaultNS != None:
                bigValue = '%s:%s' % (self.defaultNS, attrValue)
        else:
            attrNS = attrValue[:i]
            attrNCName = attrValue[i+1:]
            for shortNs, longNs in self.nsMap.iteritems():
                if shortNs == attrNS:
                    bigValue = '%s:%s' % (longNs, attrNCName)
                    break
        return bigValue

class XMLObjectFactory(xml.sax.ContentHandler):
    def __init__(self, knownTypes=None, knownNamespaces=None, xmlSource=None, createGenerics=False):
        self.rootelement = None
        if xmlSource == None:
            self.xmlSource = "unknown"
        else:
            self.xmlSource = xmlSource
        self.createGenerics = createGenerics
        self.skipper = False
        self.elementstack = []
        self.nsstack = []
        self.collectContent = None
        if (knownNamespaces == None):
            self.knownNamespaces = {}
        else:
            self.knownNamespaces = knownNamespaces
        self.reversedNamespaces = {}
        for longns, shortns in self.knownNamespaces.iteritems():
            self.reversedNamespaces[shortns] = longns
        self.knownTypes = {}
        if (knownTypes != None):
            for tag, cls in knownTypes.iteritems():
                i = tag.rfind(':')
                if i >= 0:
                    shortns = tag[:i]
                    tag = tag[i+1:]
                    if not self.reversedNamespaces.has_key(shortns):
                        errorString = 'Error unmarshalling XML document from source "%s": knownTypes specifies an unmapped short namespace "%s" for element "%s"' % (self.xmlSource, shortns, tag)
                        raise UnmarshallerException(errorString)
                    longns = self.reversedNamespaces[shortns]
                    tag = '%s:%s' % (longns, tag)
                self.knownTypes[tag] = cls
        #printKnownTypes(self.knownTypes, 'Unmarshaller.XMLObjectFactory.__init__')
        xml.sax.handler.ContentHandler.__init__(self)

    def appendElementStack(self, newElement, newNS):
        self.elementstack.append(newElement)
        if (len(self.nsstack) > 0):
            oldNS = self.nsstack[-1]
            if newNS.defaultNS == None:
                newNS.defaultNS = oldNS.defaultNS
            if newNS.targetNS == None:
                newNS.targetNS = oldNS.targetNS
            if len(newNS.nsMap) == 0:
                newNS.nsMap = oldNS.nsMap
            elif len(oldNS.nsMap) > 0:
                map = oldNS.nsMap.copy()
                map.update(newNS.nsMap)
                newNS.nsMap = map
        self.nsstack.append(newNS)
        return newNS
    
    def popElementStack(self):
        element = self.elementstack.pop()
        nse = self.nsstack.pop()
        return element, nse
        
    ## ContentHandler methods
    def startElement(self, name, attrs):
##        print '[startElement] <%s>' % (name)
        if name == 'xs:annotation' or name == 'xsd:annotation': # should use namespace mapping here
            self.skipper = True
            self.appendElementStack(Element(name, attrs.copy()), NsElement())
        if self.skipper:
            return
        if self.collectContent != None:
            strVal = '<%s' % (name)
            for aKey, aVal in attrs.items():
                strVal += (' %s="%s"' % (aKey, aVal))
            strVal += '>'
            self.collectContent.content += strVal
        xsname = name
        i = name.rfind(':')
        if i >= 0:
            nsname = name[:i]
            name = name[i+1:]
        else:
            nsname = None
        element = Element(name, attrs.copy(), xsname=xsname)
        # if the element has namespace attributes, process them and add them to our stack
        nse = NsElement()
        objtype = None
        for k in attrs.getNames():
            if k.startswith('xmlns'):
                longNs = attrs[k]
                eLongNs = longNs + '/'
                if str(eLongNs) in asDict(self.knownNamespaces):
                    longNs = eLongNs
                if k == 'xmlns':
                    nse.defaultNS = longNs
                else:
                    shortNs = k[6:]
                    nse.nsMap[shortNs] = longNs
            elif k == 'targetNamespace':
                nse.targetNS = attrs.getValue(k)
            elif k == 'objtype':
                objtype = attrs.getValue(k)
        nse = self.appendElementStack(element, nse)
        if nsname != None:
            if nse.nsMap.has_key(nsname):
                longname = '%s:%s' % (nse.nsMap[nsname], name)
##            elif objtype == None:
##                errorString = 'Error unmarshalling XML document from source "%s": tag "%s" at line "%d", column "%d" has an undefined namespace' % (self.xmlSource, xsname, self._locator.getLineNumber(), self._locator.getColumnNumber())
##                raise UnmarshallerException(errorString)
            elif self.reversedNamespaces.has_key(nsname):
                longname = '%s:%s' % (self.reversedNamespaces[nsname], name)
            else:
                longname = xsname
        elif nse.defaultNS != None:
            longname = '%s:%s' % (nse.defaultNS, name)
        else:
            longname = name
        element.objtype = objtype
        element.objclass = self.knownTypes.get(longname)
        if element.objclass == None and len(self.knownNamespaces) == 0:
            # handles common case where tags are unqualified and knownTypes are too, but there's a defaultNS
            element.objclass = self.knownTypes.get(name)
        if (hasattr(element.objclass, "__xmlcontent__")):
            self.collectContent = element

    def characters(self, content):
##        print '[characters] "%s" (%s)' % (content, type(content))
        if (content != None):
            if self.collectContent != None:
                self.collectContent.content += content
            else:
                self.elementstack[-1].content += content

    def endElement(self, name):
##        print "[endElement] </%s>" % name
        xsname = name
        i = name.rfind(':')
        if i >= 0:  # Strip namespace prefixes for now until actually looking them up in xsd
            name = name[i+1:]
        if self.skipper:
            if xsname == "xs:annotation" or xsname == "xsd:annotation":     # here too
                self.skipper = False
                self.popElementStack()
            return
        if self.collectContent != None:
            if xsname != self.collectContent.xsname:
                self.collectContent.content += ('</%s>' % (xsname))
                self.popElementStack()
                return
            else:
                self.collectContent = None
        oldChildren = self.elementstack[-1].children
        element, nse = self.popElementStack()
        if ((len(self.elementstack) > 1) and (self.elementstack[-1].getobjtype() == "None")):
            parentElement = self.elementstack[-2]
        elif (len(self.elementstack) > 0):
            parentElement = self.elementstack[-1]
        objtype = element.getobjtype()
        if (objtype == "None"):
            return
        constructorarglist = []
        if (len(element.content) > 0):
            strippedElementContent = element.content.strip()
            if (len(strippedElementContent) > 0):
                constructorarglist.append(element.content)
        # If the element requires an object, but none is known, use the GenericXMLObject class
        if ((element.objclass == None) and (element.attrs.get("objtype") == None) and ((len(element.attrs) > 0) or (len(element.children) > 0))):
            if self.createGenerics:
                element.objclass = GenericXMLObject
        obj = _objectfactory(objtype, constructorarglist, element.objclass)
        if element.objclass == GenericXMLObject:
            obj.setXMLAttributes(str(xsname), element.attrs, element.children, nse.nsMap, nse.defaultNS)
        complexType = getComplexType(obj)
        if (obj != None):
            if (hasattr(obj, "__xmlname__") and getattr(obj, "__xmlname__") == "sequence"):
                self.elementstack[-1].children = oldChildren
                return
        if (len(element.attrs) > 0) and not isinstance(obj, list):
            for attrname, attr in element.attrs.items():
                if attrname == XMLNS or attrname.startswith(XMLNS_PREFIX):
                    if attrname.startswith(XMLNS_PREFIX):
                        ns = attrname[XMLNS_PREFIX_LENGTH:]
                    else:
                        ns = ""
                    if complexType != None or element.objclass == GenericXMLObject:
                        if not hasattr(obj, "__xmlnamespaces__"):
                            obj.__xmlnamespaces__ = {ns:attr}
                        elif ns not in obj.__xmlnamespaces__:
                            if (hasattr(obj.__class__, "__xmlnamespaces__") 
                                and (obj.__xmlnamespaces__ is obj.__class__.__xmlnamespaces__)):
                                obj.__xmlnamespaces__ = dict(obj.__xmlnamespaces__)
                            obj.__xmlnamespaces__[ns] = attr
                elif not attrname == "objtype":
                    if attrname.find(":") > -1:  # Strip namespace prefixes for now until actually looking them up in xsd
                        attrname = attrname[attrname.find(":") + 1:]
                    if (complexType != None):
                        xsdElement = complexType.findElement(attrname)
                        if (xsdElement != None):
                            type = xsdElement.type
                            if (type != None):
                                if (type == TYPE_QNAME):
                                    attr = nse.expandQName(name, attrname, attr)
                                type = xsdToLangType(type)
                                ### ToDO remove maxOccurs hack after bug 177 is fixed
                                if attrname == "maxOccurs" and attr == "unbounded":
                                    attr = "-1"
                                try:
                                    attr = _objectfactory(type, attr)
                                except Exception, exceptData:
                                    errorString = 'Error unmarshalling attribute "%s" at line %d, column %d in XML document from source "%s": %s' % (attrname, self._locator.getLineNumber(), self._locator.getColumnNumber(), self.xmlSource, str(exceptData))
                                    raise UnmarshallerException(errorString)
                    try:
                        setattrignorecase(obj, _toAttrName(obj, attrname), attr)
                    except AttributeError:
                        errorString = 'Error setting value of attribute "%s" at line %d, column %d in XML document from source "%s": object type of XML element "%s" is not specified or known' % (attrname, self._locator.getLineNumber(), self._locator.getColumnNumber(), self.xmlSource, name)
                        raise UnmarshallerException(errorString)
##                    obj.__dict__[_toAttrName(obj, attrname)] = attr
        # stuff any child attributes meant to be in a sequence via the __xmlflattensequence__
        flattenDict = {}
        if hasattr(obj, "__xmlflattensequence__"):
            flatten = obj.__xmlflattensequence__
            if (isinstance(flatten, dict)):
                for sequencename, xmlnametuple in flatten.items():
                    if (xmlnametuple == None):
                        flattenDict[sequencename] = sequencename

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -