コード例 #1
0
ファイル: client.py プロジェクト: codefool/bubbles
    def envelope(self, headers, body, bodytag=None):
        '''
        Build a SOAP envelope given headers and body.
        '''
        env = ET.Element(ns.expand('soapenv:Envelope', self.nsmap), nsmap=self.nsmap)
        envheader = ET.Element(ns.expand('soapenv:Header', self.nsmap))
        envbody = ET.Element(ns.expand('soapenv:Body', self.nsmap))
        env.append(envheader)
        env.append(envbody)

        for header in headers:
            if not ET.iselement(header):
                if hasattr(header, '__xml__'):
                    header = header.__xml__()
                else:
                    raise Exception('Cannott create SOAP:header')
            envheader.append(header)
        if body is not None:
            if not ET.iselement(body):
                if hasattr(body, '__xml__'):
                    body = body.__xml__(tag=bodytag)
                else:
                    raise Exception('Cannot create SOAP:body')
            envbody.append(body)
        return env
コード例 #2
0
ファイル: client.py プロジェクト: cfrantz/bubbles
    def envelope(self, headers, body, bodytag=None):
        '''
        Build a SOAP envelope given headers and body.
        '''
        env = ET.Element(ns.expand('soapenv:Envelope', self.nsmap), nsmap=self.nsmap)
        envheader = ET.Element(ns.expand('soapenv:Header', self.nsmap))
        envbody = ET.Element(ns.expand('soapenv:Body', self.nsmap))
        env.append(envheader)
        env.append(envbody)

        for header in headers:
            if not ET.iselement(header):
                if hasattr(header, '__xml__'):
                    header = header.__xml__()
                else:
                    raise Exception('Cannott create SOAP:header')
            envheader.append(header)
        if body is not None:
            if not ET.iselement(body):
                if hasattr(body, '__xml__'):
                    body = body.__xml__(tag=bodytag)
                else:
                    raise Exception('Cannot create SOAP:body')
            envbody.append(body)
        return env
コード例 #3
0
ファイル: dobject.py プロジェクト: cfrantz/bubbles
    def __xmlstr__(self, tag=None, node=None, nsmap=None):
        '''
        Convert a DynamicObject a string containing the XML representation.

        See __xml__ for an explaination of the arguments.
        '''
        return ET.tostring(self.__xml__(tag, node, nsmap), pretty_print=True)
コード例 #4
0
ファイル: dobject.py プロジェクト: cfrantz/bubbles
    def __xmlstr__(self, tag=None, node=None, nsmap=None):
        '''
        Convert a DynamicObject a string containing the XML representation.

        See __xml__ for an explaination of the arguments.
        '''
        return ET.tostring(self.__xml__(tag, node, nsmap), pretty_print=True)
コード例 #5
0
ファイル: schema.py プロジェクト: cfrantz/bubbles
    def _make_type(self, value, type):
        '''
        Parse value and convert it to type
        '''
        iselem = False
        if ET.iselement(value):
            iselem = True
            xtype = value.get(xsi_type)
            if xtype:
                xtype = ns.expand(xtype, value.nsmap)
                (prefix, t) = ns.split(xtype)
                if prefix == ns.XS:
                    type = 'xs:'+t
                else:
                    type = xtype
            if value.get(xsi_nil) == 'true':
                return None

        if type.startswith('xs:'):
            if iselem:
                value = value.text
            c = converter(type)
            if value is not None and not c.check(value):
                value = c.fromstr(value)
        else:
            if value == "":
                value = None
            value = self.__builder__.factory(type)(value, __relax__=self.__relax__)
        return value
コード例 #6
0
ファイル: client.py プロジェクト: cfrantz/bubbles
    def __init__(self, faultxml=[], client=None):
        DynamicObject.__init__(self)
        Exception.__init__(self)

        self.code = None
        self.message = None
        self.detail = None

        for node in faultxml:
            tag = node.tag.split('}')[-1]
            if tag == 'faultcode':
                self.code = ns.split(node.text, nsmap=faultxml.nsmap)
            elif tag == 'Code':
                self.code = ns.split(node[0].text, nsmap=faultxml.nsmap)
            elif tag == 'faultstring':
                self.message = node.text
            elif tag == 'Reason':
                self.message = node[0].text
            elif tag == 'detail' or tag == 'Detail':
                faultobj = node[0]
                type = faultobj.get(ET.QName(ns.XSI, 'type'))
                if not type:
                    type = faultobj.tag
                try:
                    faultobj = client.factory(type, faultobj)
                except:
                    pass
                self.detail = faultobj
コード例 #7
0
    def _make_type(self, value, type):
        '''
        Parse value and convert it to type
        '''
        iselem = False
        if ET.iselement(value):
            iselem = True
            xtype = value.get(xsi_type)
            if xtype:
                xtype = ns.expand(xtype, value.nsmap)
                (prefix, t) = ns.split(xtype)
                if prefix == ns.XS:
                    type = 'xs:' + t
                else:
                    type = xtype
            if value.get(xsi_nil) == 'true':
                return None

        if type.startswith('xs:'):
            if iselem:
                value = value.text
            c = converter(type)
            if value is not None and not c.check(value):
                value = c.fromstr(value)
        else:
            if value == "":
                value = None
            value = self.__builder__.factory(type)(value,
                                                   __relax__=self.__relax__)
        return value
コード例 #8
0
ファイル: dobject.py プロジェクト: cfrantz/bubbles
    def __xml__(self, tag=None, node=None, nsmap=None, ignore=[]):
        '''
        Convert a DynamicObject to XML elements

        @type tag: str
        @param tag: Optional.  The name of the tag of the root node.
        @type node: L{ElementTree.Element}
        @param node: Optional.  A root node to populate.
        @type nsmap: dict
        @param nsmap: Optional.  A dictionary of namespace prefixes and namespaces to use.
        @type ignore: list
        @param ignore: Optional.  A list of fields to ignore during serialization to XML.
        @rtype: L{ElementTree.Element}
        @return: An XML Element representing this object.
        '''
        at = self.__attrchar__
        prop = self.__property__
        if tag is None:
            tag = self.__class__.__name__
        tag = self.__nsx__(tag)
        if node is None:
            node = ET.Element(tag, nsmap=nsmap)

        for key, value in self:
            if key in ignore:
                continue
            if key[0] == at:
                node.set(key[1:], unicode(value))
                continue
            name = self.__nsx__(key)
            if key == prop:
                node.text = unicode(value)
                continue
            if not isinstance(value, (list, tuple)):
                value = [value]
            for v in value:
                if isinstance(v, DynamicObject):
                    node.append(v.__xml__(key))
                elif ET.iselement(v):
                    node.append(v)
                else:
                    n = ET.Element(name)
                    if v is not None:
                        n.text = unicode(v)
                    node.append(n)
        return node
コード例 #9
0
ファイル: autoschema.py プロジェクト: cfrantz/bubbles
 def merge(self, filename):
     # We change the namespace of XMLSchema to something else because
     # the schema processor in the bubbles library can't operate on the
     # XS namespace.  Hack...
     doc = file(filename).read()
     doc = doc.replace(ns.XS, 'urn:metaschema')
     xsd = ET.fromstring(doc)
     self.schema = Schema(xsd)
コード例 #10
0
ファイル: autoschema.py プロジェクト: cfrantz/bubbles
 def merge(self, filename):
     # We change the namespace of XMLSchema to something else because
     # the schema processor in the bubbles library can't operate on the
     # XS namespace.  Hack...
     doc = file(filename).read()
     doc = doc.replace(ns.XS, 'urn:metaschema')
     xsd = ET.fromstring(doc)
     self.schema = Schema(xsd)
コード例 #11
0
ファイル: autoschema.py プロジェクト: cfrantz/bubbles
 def guess(self, filename):
     text = file(filename).read()
     text = re.sub(r'xmlns="[^"]*"', '', text)
     xml = ET.fromstring(text)
     obj = DynamicObject(xml)
     tns, tag = ns.split(xml.tag)
     root = self.complexType(tag, obj)
     el = Element(name=tag, type=root.name)
     self._addElement(self.schema, el)
コード例 #12
0
ファイル: autoschema.py プロジェクト: cfrantz/bubbles
 def guess(self, filename):
     text = file(filename).read()
     text = re.sub(r'xmlns="[^"]*"', '', text)
     xml = ET.fromstring(text)
     obj = DynamicObject(xml)
     tns, tag = ns.split(xml.tag)
     root = self.complexType(tag, obj)
     el = Element(name=tag, type=root.name)
     self._addElement(self.schema, el)
コード例 #13
0
ファイル: dobject.py プロジェクト: cfrantz/bubbles
    def __xml__(self, tag=None, node=None, nsmap=None, ignore=[]):
        '''
        Convert a DynamicObject to XML elements

        @type tag: str
        @param tag: Optional.  The name of the tag of the root node.
        @type node: L{ElementTree.Element}
        @param node: Optional.  A root node to populate.
        @type nsmap: dict
        @param nsmap: Optional.  A dictionary of namespace prefixes and namespaces to use.
        @type ignore: list
        @param ignore: Optional.  A list of fields to ignore during serialization to XML.
        @rtype: L{ElementTree.Element}
        @return: An XML Element representing this object.
        '''
        at = self.__attrchar__
        prop = self.__property__
        if tag is None:
            tag = self.__class__.__name__
        tag = self.__nsx__(tag)
        if node is None:
            node = ET.Element(tag, nsmap=nsmap)

        for key, value in self:
            if key in ignore:
                continue
            if key[0] == at:
                node.set(key[1:], unicode(value))
                continue
            name = self.__nsx__(key)
            if key == prop:
                node.text = unicode(value)
                continue
            if not isinstance(value, (list, tuple)):
                value = [value]
            for v in value:
                if isinstance(v, DynamicObject):
                    node.append(v.__xml__(key))
                elif ET.iselement(v):
                    node.append(v)
                else:
                    n = ET.Element(name)
                    if v is not None:
                        n.text = unicode(v)
                    node.append(n)
        return node
コード例 #14
0
    def validate(self, element, onerror='raise'):
        (namespace, name) = ns.split(element.tag)
        validator = self.schemas[namespace]['validator']
        if validator is None:
            validator = ET.XMLSchema(self.schemas[namespace]['root'])
            self.schemas[namespace]['validator'] = validator

        errlog = None
        if validator(element) == False:
            errlog = validator.error_log
            if onerror == 'log':
                log.error('Schema Validation Error: %s', str(errlog))
            elif onerror == 'pass':
                pass
            else:
                raise SchemaValidationError(errlog)
        return errlog
コード例 #15
0
ファイル: client.py プロジェクト: cfrantz/bubbles
    def _load(self, url):
        doc = ET.parse(urllib2.urlopen(url))
        extrans = doc.getroot().nsmap
        targetns = doc.getroot().get('targetNamespace')
        schemas = doc.findall(ns.expand('*/xs:schema'))
        for s in schemas:
            for k,v in extrans.items():
                if k not in s.nsmap:
                    s.nsmap[k] = v
            self.schemaloader.load(s, pathinfo=self.url)
        self.documents.append(doc)

        wsdls = doc.findall(ns.expand('/wsdl:import'))
        for w in wsdls:
            location = w.get('location')
            location = urljoin(url, location)
            tns = self._load(location)
            if tns:
                targetns = tns

        return targetns
コード例 #16
0
ファイル: client.py プロジェクト: codefool/bubbles
    def _load(self, url):
        doc = ET.parse(urllib2.urlopen(url))
        extrans = doc.getroot().nsmap
        targetns = doc.getroot().get('targetNamespace')
        schemas = doc.findall(ns.expand('*/xs:schema'))
        for s in schemas:
            for k,v in extrans.items():
                if k not in s.nsmap:
                    s.nsmap[k] = v
            self.schemaloader.load(s, pathinfo=self.url)
        self.documents.append(doc)

        wsdls = doc.findall(ns.expand('/wsdl:import'))
        for w in wsdls:
            location = w.get('location')
            location = urljoin(url, location)
            tns = self._load(location)
            if tns:
                targetns = tns

        return targetns
コード例 #17
0
ファイル: dobject.py プロジェクト: cfrantz/bubbles
    def __init__(self, *args, **kwargs):
        '''
        DynamicObject Constructor.

        @param args: Positional/un-named arguments or iterables.
        @param kwargs: Keyword arguments

        There are several ways to construct a new DynamicObject:

            a = DynamicObject() -- Build an empty object
            b = DynmaicObject("baz", _foo="bar") -- Build a "property" object.
            c = DynamicObject(b) -- Build a copy of "b"
            d = DynamicObject(a=1,b=2,c="foo") -- Build an object from keyword args
            e = DynamicObject(some_dict) -- Build an object from dict
            f = DynamicObject([(key, value), (key, value)]) -- Build an object from list
            g = DynamicObject(some_elementtree_elment) -- Build an object from XML
        '''
        # This bit of code is really for SchemaObject, but we can
        # just put it here so we don't have to write a special constructor
        # for SchemaObject.
        validate = kwargs.pop('__validate__', None)
        if validate is not None:
            self.__validate__ = validate
        self.__relax__ = kwargs.pop('__relax__', False)

        self.__keylist__ = []
        for arg in args:
            if isinstance(arg, (dict, list, DynamicObject)):
                self.__fromiter__(arg)
            elif ET.iselement(arg):
                self.__fromxml__(arg)
            elif arg is None:
                pass
            else:
                self.__property__ = 'value'
                # Pass it to __fromiter__ so if this is a SchemaObject,
                # the value can be consumed by _make_type.
                self.__fromiter__({'value': arg})
        self.__fromiter__(kwargs.items())
コード例 #18
0
ファイル: dobject.py プロジェクト: cfrantz/bubbles
    def __init__(self, *args, **kwargs):
        '''
        DynamicObject Constructor.

        @param args: Positional/un-named arguments or iterables.
        @param kwargs: Keyword arguments

        There are several ways to construct a new DynamicObject:

            a = DynamicObject() -- Build an empty object
            b = DynmaicObject("baz", _foo="bar") -- Build a "property" object.
            c = DynamicObject(b) -- Build a copy of "b"
            d = DynamicObject(a=1,b=2,c="foo") -- Build an object from keyword args
            e = DynamicObject(some_dict) -- Build an object from dict
            f = DynamicObject([(key, value), (key, value)]) -- Build an object from list
            g = DynamicObject(some_elementtree_elment) -- Build an object from XML
        '''
        # This bit of code is really for SchemaObject, but we can
        # just put it here so we don't have to write a special constructor
        # for SchemaObject.
        validate = kwargs.pop('__validate__', None)
        if validate is not None:
            self.__validate__ = validate
        self.__relax__ = kwargs.pop('__relax__', False)

        self.__keylist__ = []
        for arg in args:
            if isinstance(arg, (dict, list, DynamicObject)):
                self.__fromiter__(arg)
            elif ET.iselement(arg):
                self.__fromxml__(arg)
            elif arg is None:
                pass
            else:
                self.__property__ = 'value'
                # Pass it to __fromiter__ so if this is a SchemaObject,
                # the value can be consumed by _make_type.
                self.__fromiter__({'value': arg})
        self.__fromiter__(kwargs.items())
コード例 #19
0
    def __xml__(self, tag=None, node=None, nsmap=None):
        lat = len(self.__attrchar__)
        done = []
        extra = False
        if tag is None:
            tag = self.__class__.__name__
        tag = self.__nsx__(tag)
        if node is None:
            node = ET.Element(tag, nsmap=nsmap)

        # Construct reverse namespace map for doing xsi:type
        rmap = dict((v, k) for k, v in node.nsmap.items() if k is not None)

        # Iterate over the template to construct the XML representation.
        for (name, type, default, minmax, flags) in self.__template__:
            # If this field is an "xs:any" node, note it for later and skip
            if (flags & ANY):
                extra = True
                continue
            # If the field is choice/optional and doesn't exist, skip it
            if ((flags & CHOICE) or minmax[0] == 0) and name not in self:
                continue
            # Get the value
            value = self[name]
            done.append(name)

            if value is None and minmax[0] == 0 and not (flags & XSINIL):
                # Skip fields that are none and don't have to exist, as long
                # as they aren't nillable
                continue
            elif (flags & ATTRIBUTE):
                # Handle attributes.  Skip attributes that are optional
                value = converter(type).tostr(value)
                if value is None:
                    value = ''
                if value is not None or minmax[0]:
                    node.set(self.__nsx__(name[lat:], flags & QUALIFIED),
                             value)
                continue
            elif (flags & PROPERTY):
                # Property
                node.text = converter(type).tostr(value)
                continue

            qname = self.__nsx__(name)
            if not isinstance(value, (list, tuple)):
                value = [value]
            for v in value:
                if v is None and (flags & XSINIL):
                    # Nil node
                    n = ET.Element(qname, xsi_nil_true)
                    node.append(n)
                elif ET.iselement(v):
                    # User supplied XML Elements, so just add them
                    node.append(v)
                elif type.startswith('xs:'):
                    # Primitive type
                    n = ET.Element(qname)
                    n.text = converter(type).tostr(v)
                    node.append(n)
                elif flags & SIMPLE:
                    # Primitive type
                    type = self.__builder__.factory(type).__simple__
                    n = ET.Element(qname)
                    n.text = converter(type).tostr(v)
                    node.append(n)
                elif isinstance(v, DynamicObject):
                    # Dynamic object or subclass, so marshall and append
                    n = v.__xml__(name)
                    if type != v.__class__.__name__:
                        (namespace, datatype) = ns.split(v.__class__.__name__)
                        n.set(xsi_type, '%s:%s' % (rmap[namespace], datatype))
                    node.append(n)
                elif v == '':
                    # Carry-over for dealing with SUDS bug
                    pass
                else:
                    if not self.__relax__:
                        raise TypeError('Unknown type', name, type)

        # If there was an xs:any node, fall back to the schemaless marshaller
        # in the base class
        if extra:
            DynamicObject.__xml__(self, tag, node, ignore=done)
        return node
コード例 #20
0
ファイル: client.py プロジェクト: cfrantz/bubbles
    def invoke(self, operation, *args, **kwargs):
        '''
        Invoke a SOAP operation.
        '''
        self._reqno += 1
        retxml = kwargs.pop('__retxml__', self.retxml)
        timeout = kwargs.pop('__timeout__', self.timeout)
        transport_options = kwargs.pop('__transport__', {})
        # Create an instance of the request message and initialize
        # the object from the arguments
        param = self.factory(operation.imsg)
        tmpl = param.__template__
        for k,v in zip((t[0] for t in tmpl), args):
            param[k] = v
        for k,v in kwargs.items():
            param[k] = v

        # Build the soap envelope and set the http headers
        payload = self.envelope(self.headers, param, operation.imsg)
        httphdr = { 'Content-Type': 'text/xml', 'SOAPAction': operation.action }
        httphdr.update(self.httphdr)

        # Construct and issue the request, read the response
        payload = ET.tostring(payload, pretty_print=True)
        log.debug('=== SOAP REQUEST ===\n%s', payload)
        req = urllib2.Request(self.url, payload, httphdr)
        try:
            if self._inject:
                xml = ET.fromstring(self._inject.next())
            else:
                if hasattr(self.transport, 'open'):
                    rsp = self.transport.open(req, timeout=timeout, **transport_options)
                else:
                    rsp = self.transport.urlopen(req, timeout=timeout, **transport_options)
                xml = ET.parse(rsp)
        except urllib2.HTTPError as ex:
            xml = ET.parse(ex)

        log.debug('=== SOAP RESPONSE ===\n%s', xmlstr(xml))
        # Get the soap body
        retval = xml.find(ns.expand('soapenv:Body', self.nsmap))
        if not retxml:
            # Does the body contain any nodes?
            if len(retval):
                # Get the first child and examine it
                retval = retval[0]
                namespace, tag = ns.split(retval.tag)
                # If it's a fault, convert it to an exception
                if tag == 'Fault':
                    raise SoapFault(retval, self)
                # Otherwise, deserialize
                obj = self.factory(operation.omsg, retval)
                # If the deserialized
                # object has only one item, return that item, otherwise the
                # whole object
                #
                # This is so if the return value is a single primitive type
                # (like a string), you don't have to dig into an object just
                # to get at the single primitive return value
                if len(obj) == 1:
                    obj = obj[0]
                retval = obj
            else:
                retval = None

        return retval
コード例 #21
0
ファイル: schema.py プロジェクト: cfrantz/bubbles
    def load(self, schema, force=False, fragment=False, pathinfo='', basecls=None):
        '''
        Load and pre-process an XML schema.

        @type schema: L{ElementTree.Element} or URL
        @param schema: A schema to load.
        @type force: bool
        @param force: Optional.  Reload an already loaded schema.
        @type fragment: bool
        @param fragment: Optional.  The schema is actually a fragment of a
            an already-loaded schema and should be integrated with it.
        @type pathinfo: str
        @param pathinfo: Optional.  A URL to help with loading the schema.
            Usually used by SchemaLoader to process xs:import directives.
        @rtype: str
        @return: The targetNamespace of the loaded schema
        '''
        # Is schema already parsed 
        if ET.iselement(schema):
            root = schema
        else:
            schema = urljoin(pathinfo, schema)
            root = ET.parse(u2.urlopen(schema)).getroot()

        # Get the target namespace.  Exit early if we already know this schema.
        targetNamespace = root.get('targetNamespace')
        if targetNamespace in self.schemas and not (force or fragment):
            return targetNamespace

        # Add a new entry to our dictionary
        if not fragment:
            self.schemas[targetNamespace] = { 'root': root, 'types': {}, 'elements': {}, 'groups': {}, 'validator': None, 'basecls': basecls }

        # Update our "all namespaces" dictionary and get references to the
        # various subdictionaries we'll need
        self.allns.update(root.nsmap)
        self.revns.update((v,k) for k,v in root.nsmap.items() if k not in (None, 'tns'))
        types = self.schemas[targetNamespace]['types']
        elements = self.schemas[targetNamespace]['elements']
        groups = self.schemas[targetNamespace]['groups']

        # Process includes
        includes = []
        while True:
            # Get the list of includes
            inclist = root.findall(ns.expand('xs:include'))
            if not inclist:
                break

            for el in inclist:
                # remove it from the document
                root.remove(el)
                
                # Get the schemaLocation and compute the URL
                location = el.get('schemaLocation')
                if location in includes:
                    # skip if we've processed this schema
                    continue
                includes.append(location)
                url = urljoin(pathinfo, location)

                # Parse the XML and append it to the root document
                # We probably *should* include it into the place where the
                # xs:include node was, but for now, punt and append it
                # to the end of the document
                inc = ET.parse(u2.urlopen(url)).getroot()
                root.extend(inc)

        # Process imports
        for el in root.findall(ns.expand('xs:import')):
            location = el.get('schemaLocation')
            if location:
                self.load(location, pathinfo=pathinfo)
        # Find all first-level tags we care about and reference them
        # in the types/elements/groups dictionaries
        for el in root.findall(ns.expand('xs:complexType')):
            types[el.get('name')] = el
        for el in root.findall(ns.expand('xs:simpleType')):
            types[el.get('name')] = el
        for el in root.findall(ns.expand('xs:element')):
            elements[el.get('name')] = el
        for el in root.findall(ns.expand('xs:group')):
            groups[el.get('name')] = el

        # If this is a schema fragment, integrate it into the
        # original schema element tree in memory
        if fragment:
            realroot = self.schemas[targetNamespace]['root']
            nsmap = dict(realroot.nsmap)
            nsmap.update(root.nsmap)
            attrib = dict(realroot.attrib)
            attrib.update(root.attrib)
            newroot = ET.Element(realroot.tag, attrib=attrib, nsmap=nsmap)
            newroot.text = realroot.text

            newroot.extend(realroot.getchildren())
            newroot.extend(root.getchildren())
            self.schemas[targetNamespace]['root'] = newroot

        return targetNamespace
コード例 #22
0
ファイル: schema.py プロジェクト: cfrantz/bubbles
    def __xml__(self, tag=None, node=None, nsmap=None):
        lat = len(self.__attrchar__)
        done = []
        extra = False
        if tag is None:
            tag = self.__class__.__name__
        tag = self.__nsx__(tag)
        if node is None:
            node = ET.Element(tag, nsmap=nsmap)

        # Construct reverse namespace map for doing xsi:type
        rmap = dict((v,k) for k, v in node.nsmap.items() if k is not None)

        # Iterate over the template to construct the XML representation.
        for (name, type, default, minmax, flags) in self.__template__:
            # If this field is an "xs:any" node, note it for later and skip
            if (flags & ANY):
                extra = True
                continue
            # If the field is choice/optional and doesn't exist, skip it
            if ((flags & CHOICE) or minmax[0] == 0) and name not in self:
                continue
            # Get the value
            value = self[name]
            done.append(name)
            
            if value is None and minmax[0] == 0 and not (flags & XSINIL):
                # Skip fields that are none and don't have to exist, as long
                # as they aren't nillable
                continue
            elif (flags & ATTRIBUTE):
                # Handle attributes.  Skip attributes that are optional
                value = converter(type).tostr(value)
                if value is None:
                    value = ''
                if value is not None or minmax[0]:
                    node.set(self.__nsx__(name[lat:], flags & QUALIFIED), value)
                continue
            elif (flags & PROPERTY):
                # Property
                node.text = converter(type).tostr(value)
                continue

            qname = self.__nsx__(name)
            if not isinstance(value, (list, tuple)):
                value = [value]
            for v in value:
                if v is None and (flags & XSINIL):
                    # Nil node
                    n = ET.Element(qname, xsi_nil_true)
                    node.append(n)
                elif ET.iselement(v):
                    # User supplied XML Elements, so just add them
                    node.append(v)
                elif type.startswith('xs:'):
                    # Primitive type
                    n = ET.Element(qname)
                    n.text = converter(type).tostr(v)
                    node.append(n)
                elif flags & SIMPLE:
                    # Primitive type
                    type = self.__builder__.factory(type).__simple__
                    n = ET.Element(qname)
                    n.text = converter(type).tostr(v)
                    node.append(n)
                elif isinstance(v, DynamicObject):
                    # Dynamic object or subclass, so marshall and append
                    n = v.__xml__(name)
                    if type != v.__class__.__name__:
                        (namespace, datatype) = ns.split(v.__class__.__name__)
                        n.set(xsi_type, '%s:%s' % (rmap[namespace], datatype))
                    node.append(n)
                elif v == '':
                    # Carry-over for dealing with SUDS bug
                    pass
                else:
                    if not self.__relax__:
                        raise TypeError('Unknown type', name, type)

        # If there was an xs:any node, fall back to the schemaless marshaller
        # in the base class
        if extra:
            DynamicObject.__xml__(self, tag, node, ignore=done)
        return node
コード例 #23
0
ファイル: client.py プロジェクト: codefool/bubbles
    def invoke(self, operation, *args, **kwargs):
        '''
        Invoke a SOAP operation.
        '''
        self._reqno += 1
        retxml = kwargs.pop('__retxml__', self.retxml)
        timeout = kwargs.pop('__timeout__', self.timeout)
        transport_options = kwargs.pop('__transport__', {})
        # Create an instance of the request message and initialize
        # the object from the arguments
        param = self.factory(operation.imsg)
        tmpl = param.__template__
        for k,v in zip((t[0] for t in tmpl), args):
            param[k] = v
        for k,v in kwargs.items():
            param[k] = v

        # Build the soap envelope and set the http headers
        payload = self.envelope(self.headers, param, operation.imsg)
        httphdr = { 'Content-Type': 'text/xml', 'SOAPAction': operation.action }
        httphdr.update(self.httphdr)

        # Construct and issue the request, read the response
        payload = ET.tostring(payload, pretty_print=True)
        log.debug('=== SOAP REQUEST ===\n%s', re.sub(r'password>.*?<', r'password>*****<', payload ))
        req = urllib2.Request(self.url, payload, httphdr)
        try:
            if self._inject:
                xml = ET.fromstring(self._inject.next())
            else:
                if hasattr(self.transport, 'open'):
                    rsp = self.transport.open(req, timeout=timeout, **transport_options)
                else:
                    rsp = self.transport.urlopen(req, timeout=timeout, **transport_options)
                xml = ET.parse(rsp)
        except urllib2.HTTPError as ex:
            xml = ET.parse(ex)

        log.debug('=== SOAP RESPONSE ===\n%s', xmlstr(xml))
        # Get the soap body
        retval = xml.find(ns.expand('soapenv:Body', self.nsmap))
        if not retxml:
            # Does the body contain any nodes?
            if len(retval):
                # Get the first child and examine it
                retval = retval[0]
                namespace, tag = ns.split(retval.tag)
                # If it's a fault, convert it to an exception
                if tag == 'Fault':
                    raise SoapFault(retval, self)
                # Otherwise, deserialize
                obj = self.factory(operation.omsg, retval)
                # If the deserialized
                # object has only one item, return that item, otherwise the
                # whole object
                #
                # This is so if the return value is a single primitive type
                # (like a string), you don't have to dig into an object just
                # to get at the single primitive return value
                if len(obj) == 1:
                    obj = obj[0]
                retval = obj
            else:
                retval = None

        return retval
コード例 #24
0
import threading
import re
import urllib2 as u2
from urlparse import urljoin
from logging import getLogger

log = getLogger(__name__)

XSINIL = 1
PROPERTY = 2
ATTRIBUTE = 4
CHOICE = 8
ANY = 16
QUALIFIED = 32
SIMPLE = 64
xsi_type = ET.QName(ns.XSI, 'type')
xsi_nil = ET.QName(ns.XSI, 'nil')
xsi_nil_true = {xsi_nil: "true"}


class SchemaValidationError(Exception):
    pass


class _SchemaLoader:
    '''
    The SchemaLoader is a container for loading and pre-processing XML
    Schemas.
    '''
    def __init__(self):
        self.schemas = {}
コード例 #25
0
    def load(self,
             schema,
             force=False,
             fragment=False,
             pathinfo='',
             basecls=None):
        '''
        Load and pre-process an XML schema.

        @type schema: L{ElementTree.Element} or URL
        @param schema: A schema to load.
        @type force: bool
        @param force: Optional.  Reload an already loaded schema.
        @type fragment: bool
        @param fragment: Optional.  The schema is actually a fragment of a
            an already-loaded schema and should be integrated with it.
        @type pathinfo: str
        @param pathinfo: Optional.  A URL to help with loading the schema.
            Usually used by SchemaLoader to process xs:import directives.
        @rtype: str
        @return: The targetNamespace of the loaded schema
        '''
        # Is schema already parsed
        if ET.iselement(schema):
            root = schema
        else:
            schema = urljoin(pathinfo, schema)
            root = ET.parse(u2.urlopen(schema)).getroot()

        # Get the target namespace.  Exit early if we already know this schema.
        targetNamespace = root.get('targetNamespace')
        if targetNamespace in self.schemas and not (force or fragment):
            return targetNamespace

        # Add a new entry to our dictionary
        if not fragment:
            self.schemas[targetNamespace] = {
                'root': root,
                'types': {},
                'elements': {},
                'groups': {},
                'validator': None,
                'basecls': basecls
            }

        # Update our "all namespaces" dictionary and get references to the
        # various subdictionaries we'll need
        self.allns.update(root.nsmap)
        self.revns.update(
            (v, k) for k, v in root.nsmap.items() if k not in (None, 'tns'))
        types = self.schemas[targetNamespace]['types']
        elements = self.schemas[targetNamespace]['elements']
        groups = self.schemas[targetNamespace]['groups']

        # Process includes
        includes = []
        while True:
            # Get the list of includes
            inclist = root.findall(ns.expand('xs:include'))
            if not inclist:
                break

            for el in inclist:
                # remove it from the document
                root.remove(el)

                # Get the schemaLocation and compute the URL
                location = el.get('schemaLocation')
                if location in includes:
                    # skip if we've processed this schema
                    continue
                includes.append(location)
                url = urljoin(pathinfo, location)

                # Parse the XML and append it to the root document
                # We probably *should* include it into the place where the
                # xs:include node was, but for now, punt and append it
                # to the end of the document
                inc = ET.parse(u2.urlopen(url)).getroot()
                root.extend(inc)

        # Process imports
        for el in root.findall(ns.expand('xs:import')):
            location = el.get('schemaLocation')
            if location:
                self.load(location, pathinfo=pathinfo)
        # Find all first-level tags we care about and reference them
        # in the types/elements/groups dictionaries
        for el in root.findall(ns.expand('xs:complexType')):
            types[el.get('name')] = el
        for el in root.findall(ns.expand('xs:simpleType')):
            types[el.get('name')] = el
        for el in root.findall(ns.expand('xs:element')):
            elements[el.get('name')] = el
        for el in root.findall(ns.expand('xs:group')):
            groups[el.get('name')] = el

        # If this is a schema fragment, integrate it into the
        # original schema element tree in memory
        if fragment:
            realroot = self.schemas[targetNamespace]['root']
            nsmap = dict(realroot.nsmap)
            nsmap.update(root.nsmap)
            attrib = dict(realroot.attrib)
            attrib.update(root.attrib)
            newroot = ET.Element(realroot.tag, attrib=attrib, nsmap=nsmap)
            newroot.text = realroot.text

            newroot.extend(realroot.getchildren())
            newroot.extend(root.getchildren())
            self.schemas[targetNamespace]['root'] = newroot

        return targetNamespace