--- /dev/null
+#TODO add the license
+#I had to rewrite this class because the python MIME email.mime (version 2.5)
+#are buggy, they use \n instead \r\n for new line which is not compliant
+#to standard!
+# http://bugs.python.org/issue5525
+
+#TODO do not load all the message in memory stream it from the disk
+
+import re
+import random
+import sys
+
+
+#new line
+NL='\r\n'
+
+_width = len(repr(sys.maxint-1))
+_fmt = '%%0%dd' % _width
+
+class MIMEMessage:
+
+ def __init__(self):
+ self._files = []
+ self._xmlMessage = ""
+ self._startCID = ""
+ self._boundary = ""
+
+ def makeBoundary(self):
+ #create the boundary
+ msgparts = []
+ msgparts.append(self._xmlMessage)
+ for i in self._files:
+ msgparts.append(i.read())
+ #this sucks, all in memory
+ alltext = NL.join(msgparts)
+ self._boundary = _make_boundary(alltext)
+ #maybe I can save some memory
+ del alltext
+ del msgparts
+ self._startCID = "<" + (_fmt % random.randrange(sys.maxint)) + (_fmt % random.randrange(sys.maxint)) + ">"
+
+
+ def toString(self):
+ '''it return a string with the MIME message'''
+ if len(self._boundary) == 0:
+ #the makeBoundary hasn't been called yet
+ self.makeBoundary()
+ #ok we have everything let's start to spit the message out
+ #first the XML
+ returnstr = NL + "--" + self._boundary + NL
+ returnstr += "Content-Type: text/xml; charset=\"us-ascii\"" + NL
+ returnstr += "Content-Transfer-Encoding: 7bit" + NL
+ returnstr += "Content-Id: " + self._startCID + NL + NL
+ returnstr += self._xmlMessage + NL
+ #then the files
+ for file in self._files:
+ returnstr += "--" + self._boundary + NL
+ returnstr += "Content-Type: application/octet-stream" + NL
+ returnstr += "Content-Transfer-Encoding: binary" + NL
+ returnstr += "Content-Id: <" + str(id(file)) + ">" + NL + NL
+ file.seek(0)
+ returnstr += file.read() + NL
+ #closing boundary
+ returnstr += "--" + self._boundary + "--" + NL
+ return returnstr
+
+ def attachFile(self, file):
+ '''
+ it adds a file to this attachment
+ '''
+ self._files.append(file)
+
+ def addXMLMessage(self, xmlMessage):
+ '''
+ it adds the XML message. we can have only one XML SOAP message
+ '''
+ self._xmlMessage = xmlMessage
+
+ def getBoundary(self):
+ '''
+ this function returns the string used in the mime message as a
+ boundary. First the write method as to be called
+ '''
+ return self._boundary
+
+ def getStartCID(self):
+ '''
+ This function returns the CID of the XML message
+ '''
+ return self._startCID
+
+
+def _make_boundary(text=None):
+ #some code taken from python stdlib
+ # Craft a random boundary. If text is given, ensure that the chosen
+ # boundary doesn't appear in the text.
+ token = random.randrange(sys.maxint)
+ boundary = ('=' * 10) + (_fmt % token) + '=='
+ if text is None:
+ return boundary
+ b = boundary
+ counter = 0
+ while True:
+ cre = re.compile('^--' + re.escape(b) + '(--)?$', re.MULTILINE)
+ if not cre.search(text):
+ break
+ b = boundary + '.' + str(counter)
+ counter += 1
+ return b
+
--- /dev/null
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+"""Namespace module, so you don't need PyXML
+"""
+
+ident = "$Id$"
+try:
+ from xml.ns import SOAP, SCHEMA, WSDL, XMLNS, DSIG, ENCRYPTION
+ DSIG.C14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
+
+except:
+ class SOAP:
+ ENV = "http://schemas.xmlsoap.org/soap/envelope/"
+ ENC = "http://schemas.xmlsoap.org/soap/encoding/"
+ ACTOR_NEXT = "http://schemas.xmlsoap.org/soap/actor/next"
+
+ class SCHEMA:
+ XSD1 = "http://www.w3.org/1999/XMLSchema"
+ XSD2 = "http://www.w3.org/2000/10/XMLSchema"
+ XSD3 = "http://www.w3.org/2001/XMLSchema"
+ XSD_LIST = [ XSD1, XSD2, XSD3]
+ XSI1 = "http://www.w3.org/1999/XMLSchema-instance"
+ XSI2 = "http://www.w3.org/2000/10/XMLSchema-instance"
+ XSI3 = "http://www.w3.org/2001/XMLSchema-instance"
+ XSI_LIST = [ XSI1, XSI2, XSI3 ]
+ BASE = XSD3
+
+ class WSDL:
+ BASE = "http://schemas.xmlsoap.org/wsdl/"
+ BIND_HTTP = "http://schemas.xmlsoap.org/wsdl/http/"
+ BIND_MIME = "http://schemas.xmlsoap.org/wsdl/mime/"
+ BIND_SOAP = "http://schemas.xmlsoap.org/wsdl/soap/"
+ BIND_SOAP12 = "http://schemas.xmlsoap.org/wsdl/soap12/"
+
+ class XMLNS:
+ BASE = "http://www.w3.org/2000/xmlns/"
+ XML = "http://www.w3.org/XML/1998/namespace"
+ HTML = "http://www.w3.org/TR/REC-html40"
+
+ class DSIG:
+ BASE = "http://www.w3.org/2000/09/xmldsig#"
+ C14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
+ C14N_COMM = "http://www.w3.org/TR/2000/CR-xml-c14n-20010315#WithComments"
+ C14N_EXCL = "http://www.w3.org/2001/10/xml-exc-c14n#"
+ DIGEST_MD2 = "http://www.w3.org/2000/09/xmldsig#md2"
+ DIGEST_MD5 = "http://www.w3.org/2000/09/xmldsig#md5"
+ DIGEST_SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1"
+ ENC_BASE64 = "http://www.w3.org/2000/09/xmldsig#base64"
+ ENVELOPED = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
+ HMAC_SHA1 = "http://www.w3.org/2000/09/xmldsig#hmac-sha1"
+ SIG_DSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"
+ SIG_RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
+ XPATH = "http://www.w3.org/TR/1999/REC-xpath-19991116"
+ XSLT = "http://www.w3.org/TR/1999/REC-xslt-19991116"
+
+ class ENCRYPTION:
+ BASE = "http://www.w3.org/2001/04/xmlenc#"
+ BLOCK_3DES = "http://www.w3.org/2001/04/xmlenc#des-cbc"
+ BLOCK_AES128 = "http://www.w3.org/2001/04/xmlenc#aes128-cbc"
+ BLOCK_AES192 = "http://www.w3.org/2001/04/xmlenc#aes192-cbc"
+ BLOCK_AES256 = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
+ DIGEST_RIPEMD160 = "http://www.w3.org/2001/04/xmlenc#ripemd160"
+ DIGEST_SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256"
+ DIGEST_SHA512 = "http://www.w3.org/2001/04/xmlenc#sha512"
+ KA_DH = "http://www.w3.org/2001/04/xmlenc#dh"
+ KT_RSA_1_5 = "http://www.w3.org/2001/04/xmlenc#rsa-1_5"
+ KT_RSA_OAEP = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"
+ STREAM_ARCFOUR = "http://www.w3.org/2001/04/xmlenc#arcfour"
+ WRAP_3DES = "http://www.w3.org/2001/04/xmlenc#kw-3des"
+ WRAP_AES128 = "http://www.w3.org/2001/04/xmlenc#kw-aes128"
+ WRAP_AES192 = "http://www.w3.org/2001/04/xmlenc#kw-aes192"
+ WRAP_AES256 = "http://www.w3.org/2001/04/xmlenc#kw-aes256"
+
+
+class WSRF_V1_2:
+ '''OASIS WSRF Specifications Version 1.2
+ '''
+ class LIFETIME:
+ XSD_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceLifetime-1.2-draft-01.xsd"
+ XSD_DRAFT4 = "http://docs.oasis-open.org/wsrf/2004/11/wsrf-WS-ResourceLifetime-1.2-draft-04.xsd"
+
+ WSDL_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceLifetime-1.2-draft-01.wsdl"
+ WSDL_DRAFT4 = "http://docs.oasis-open.org/wsrf/2004/11/wsrf-WS-ResourceLifetime-1.2-draft-04.wsdl"
+ LATEST = WSDL_DRAFT4
+ WSDL_LIST = (WSDL_DRAFT1, WSDL_DRAFT4)
+ XSD_LIST = (XSD_DRAFT1, XSD_DRAFT4)
+
+ class PROPERTIES:
+ XSD_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.xsd"
+ XSD_DRAFT5 = "http://docs.oasis-open.org/wsrf/2004/11/wsrf-WS-ResourceProperties-1.2-draft-05.xsd"
+
+ WSDL_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.wsdl"
+ WSDL_DRAFT5 = "http://docs.oasis-open.org/wsrf/2004/11/wsrf-WS-ResourceProperties-1.2-draft-05.wsdl"
+ LATEST = WSDL_DRAFT5
+ WSDL_LIST = (WSDL_DRAFT1, WSDL_DRAFT5)
+ XSD_LIST = (XSD_DRAFT1, XSD_DRAFT5)
+
+ class BASENOTIFICATION:
+ XSD_DRAFT1 = "http://docs.oasis-open.org/wsn/2004/06/wsn-WS-BaseNotification-1.2-draft-01.xsd"
+
+ WSDL_DRAFT1 = "http://docs.oasis-open.org/wsn/2004/06/wsn-WS-BaseNotification-1.2-draft-01.wsdl"
+ LATEST = WSDL_DRAFT1
+ WSDL_LIST = (WSDL_DRAFT1,)
+ XSD_LIST = (XSD_DRAFT1,)
+
+ class BASEFAULTS:
+ XSD_DRAFT1 = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-BaseFaults-1.2-draft-01.xsd"
+ XSD_DRAFT3 = "http://docs.oasis-open.org/wsrf/2004/11/wsrf-WS-BaseFaults-1.2-draft-03.xsd"
+ #LATEST = DRAFT3
+ #WSDL_LIST = (WSDL_DRAFT1, WSDL_DRAFT3)
+ XSD_LIST = (XSD_DRAFT1, XSD_DRAFT3)
+
+WSRF = WSRF_V1_2
+WSRFLIST = (WSRF_V1_2,)
+
+
+class OASIS:
+ '''URLs for Oasis specifications
+ '''
+ WSSE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
+ UTILITY = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
+
+ class X509TOKEN:
+ Base64Binary = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
+ STRTransform = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0"
+ PKCS7 = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#PKCS7"
+ X509 = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509"
+ X509PKIPathv1 = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1"
+ X509v3SubjectKeyIdentifier = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3SubjectKeyIdentifier"
+
+ LIFETIME = WSRF_V1_2.LIFETIME.XSD_DRAFT1
+ PROPERTIES = WSRF_V1_2.PROPERTIES.XSD_DRAFT1
+ BASENOTIFICATION = WSRF_V1_2.BASENOTIFICATION.XSD_DRAFT1
+ BASEFAULTS = WSRF_V1_2.BASEFAULTS.XSD_DRAFT1
+
+
+class APACHE:
+ '''This name space is defined by AXIS and it is used for the TC in TCapache.py,
+ Map and file attachment (DataHandler)
+ '''
+ AXIS_NS = "http://xml.apache.org/xml-soap"
+
+
+class WSTRUST:
+ BASE = "http://schemas.xmlsoap.org/ws/2004/04/trust"
+ ISSUE = "http://schemas.xmlsoap.org/ws/2004/04/trust/Issue"
+
+class WSSE:
+ BASE = "http://schemas.xmlsoap.org/ws/2002/04/secext"
+ TRUST = WSTRUST.BASE
+
+
+class WSU:
+ BASE = "http://schemas.xmlsoap.org/ws/2002/04/utility"
+ UTILITY = "http://schemas.xmlsoap.org/ws/2002/07/utility"
+
+
+class WSR:
+ PROPERTIES = "http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceProperties"
+ LIFETIME = "http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceLifetime"
+
+
+class WSA200508:
+ ADDRESS = "http://www.w3.org/2005/08/addressing"
+ ANONYMOUS = "%s/anonymous" %ADDRESS
+ FAULT = "%s/fault" %ADDRESS
+
+class WSA200408:
+ ADDRESS = "http://schemas.xmlsoap.org/ws/2004/08/addressing"
+ ANONYMOUS = "%s/role/anonymous" %ADDRESS
+ FAULT = "%s/fault" %ADDRESS
+
+class WSA200403:
+ ADDRESS = "http://schemas.xmlsoap.org/ws/2004/03/addressing"
+ ANONYMOUS = "%s/role/anonymous" %ADDRESS
+ FAULT = "%s/fault" %ADDRESS
+
+class WSA200303:
+ ADDRESS = "http://schemas.xmlsoap.org/ws/2003/03/addressing"
+ ANONYMOUS = "%s/role/anonymous" %ADDRESS
+ FAULT = None
+
+
+WSA = WSA200408
+WSA_LIST = (WSA200508, WSA200408, WSA200403, WSA200303)
+
+class _WSAW(str):
+ """ Define ADDRESS attribute to be compatible with WSA* layout """
+ ADDRESS = property(lambda s: s)
+
+WSAW200605 = _WSAW("http://www.w3.org/2006/05/addressing/wsdl")
+
+WSAW_LIST = (WSAW200605,)
+
+class WSP:
+ POLICY = "http://schemas.xmlsoap.org/ws/2002/12/policy"
+
+class BEA:
+ SECCONV = "http://schemas.xmlsoap.org/ws/2004/04/sc"
+ SCTOKEN = "http://schemas.xmlsoap.org/ws/2004/04/security/sc/sct"
+
+class GLOBUS:
+ SECCONV = "http://wsrf.globus.org/core/2004/07/security/secconv"
+ CORE = "http://www.globus.org/namespaces/2004/06/core"
+ SIG = "http://www.globus.org/2002/04/xmlenc#gssapi-sign"
+ TOKEN = "http://www.globus.org/ws/2004/09/security/sc#GSSAPI_GSI_TOKEN"
+
+ZSI_SCHEMA_URI = 'http://www.zolera.com/schemas/ZSI/'
--- /dev/null
+"""Based on code from timeout_socket.py, with some tweaks for compatibility.
+ These tweaks should really be rolled back into timeout_socket, but it's
+ not totally clear who is maintaining it at this point. In the meantime,
+ we'll use a different module name for our tweaked version to avoid any
+ confusion.
+
+ The original timeout_socket is by:
+
+ Scott Cotton <scott@chronis.pobox.com>
+ Lloyd Zusman <ljz@asfast.com>
+ Phil Mayes <pmayes@olivebr.com>
+ Piers Lauder <piers@cs.su.oz.au>
+ Radovan Garabik <garabik@melkor.dnp.fmph.uniba.sk>
+"""
+
+ident = "$Id$"
+
+import string, socket, select, errno
+
+WSAEINVAL = getattr(errno, 'WSAEINVAL', 10022)
+
+
+class TimeoutSocket:
+ """A socket imposter that supports timeout limits."""
+
+ def __init__(self, timeout=20, sock=None):
+ self.timeout = float(timeout)
+ self.inbuf = ''
+ if sock is None:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock = sock
+ self.sock.setblocking(0)
+ self._rbuf = ''
+ self._wbuf = ''
+
+ def __getattr__(self, name):
+ # Delegate to real socket attributes.
+ return getattr(self.sock, name)
+
+ def connect(self, *addr):
+ timeout = self.timeout
+ sock = self.sock
+ try:
+ # Non-blocking mode
+ sock.setblocking(0)
+ apply(sock.connect, addr)
+ sock.setblocking(timeout != 0)
+ return 1
+ except socket.error,why:
+ if not timeout:
+ raise
+ sock.setblocking(1)
+ if len(why.args) == 1:
+ code = 0
+ else:
+ code, why = why
+ if code not in (
+ errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK
+ ):
+ raise
+ r,w,e = select.select([],[sock],[],timeout)
+ if w:
+ try:
+ apply(sock.connect, addr)
+ return 1
+ except socket.error,why:
+ if len(why.args) == 1:
+ code = 0
+ else:
+ code, why = why
+ if code in (errno.EISCONN, WSAEINVAL):
+ return 1
+ raise
+ raise TimeoutError('socket connect() timeout.')
+
+ def send(self, data, flags=0):
+ total = len(data)
+ next = 0
+ while 1:
+ r, w, e = select.select([],[self.sock], [], self.timeout)
+ if w:
+ buff = data[next:next + 8192]
+ sent = self.sock.send(buff, flags)
+ next = next + sent
+ if next == total:
+ return total
+ continue
+ raise TimeoutError('socket send() timeout.')
+
+ def recv(self, amt, flags=0):
+ if select.select([self.sock], [], [], self.timeout)[0]:
+ return self.sock.recv(amt, flags)
+ raise TimeoutError('socket recv() timeout.')
+
+ buffsize = 4096
+ handles = 1
+
+ def makefile(self, mode="r", buffsize=-1):
+ self.handles = self.handles + 1
+ self.mode = mode
+ return self
+
+ def close(self):
+ self.handles = self.handles - 1
+ if self.handles == 0 and self.sock.fileno() >= 0:
+ self.sock.close()
+
+ def read(self, n=-1):
+ if not isinstance(n, type(1)):
+ n = -1
+ if n >= 0:
+ k = len(self._rbuf)
+ if n <= k:
+ data = self._rbuf[:n]
+ self._rbuf = self._rbuf[n:]
+ return data
+ n = n - k
+ L = [self._rbuf]
+ self._rbuf = ""
+ while n > 0:
+ new = self.recv(max(n, self.buffsize))
+ if not new: break
+ k = len(new)
+ if k > n:
+ L.append(new[:n])
+ self._rbuf = new[n:]
+ break
+ L.append(new)
+ n = n - k
+ return "".join(L)
+ k = max(4096, self.buffsize)
+ L = [self._rbuf]
+ self._rbuf = ""
+ while 1:
+ new = self.recv(k)
+ if not new: break
+ L.append(new)
+ k = min(k*2, 1024**2)
+ return "".join(L)
+
+ def readline(self, limit=-1):
+ data = ""
+ i = self._rbuf.find('\n')
+ while i < 0 and not (0 < limit <= len(self._rbuf)):
+ new = self.recv(self.buffsize)
+ if not new: break
+ i = new.find('\n')
+ if i >= 0: i = i + len(self._rbuf)
+ self._rbuf = self._rbuf + new
+ if i < 0: i = len(self._rbuf)
+ else: i = i+1
+ if 0 <= limit < len(self._rbuf): i = limit
+ data, self._rbuf = self._rbuf[:i], self._rbuf[i:]
+ return data
+
+ def readlines(self, sizehint = 0):
+ total = 0
+ list = []
+ while 1:
+ line = self.readline()
+ if not line: break
+ list.append(line)
+ total += len(line)
+ if sizehint and total >= sizehint:
+ break
+ return list
+
+ def writelines(self, list):
+ self.send(''.join(list))
+
+ def write(self, data):
+ self.send(data)
+
+ def flush(self):
+ pass
+
+
+class TimeoutError(Exception):
+ pass
--- /dev/null
+"""
+A more or less complete user-defined wrapper around tuple objects.
+Adapted version of the standard library's UserList.
+
+Taken from Stefan Schwarzer's ftputil library, available at
+<http://www.ndh.net/home/sschwarzer/python/python_software.html>, and used under this license:
+
+
+
+
+Copyright (C) 1999, Stefan Schwarzer
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+- Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+- Neither the name of the above author nor the names of the
+ contributors to the software may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+
+
+
+
+# $Id$
+
+#XXX tuple instances (in Python 2.2) contain also:
+# __class__, __delattr__, __getattribute__, __hash__, __new__,
+# __reduce__, __setattr__, __str__
+# What about these?
+
+class UserTuple:
+ def __init__(self, inittuple=None):
+ self.data = ()
+ if inittuple is not None:
+ # XXX should this accept an arbitrary sequence?
+ if type(inittuple) == type(self.data):
+ self.data = inittuple
+ elif isinstance(inittuple, UserTuple):
+ # this results in
+ # self.data is inittuple.data
+ # but that's ok for tuples because they are
+ # immutable. (Builtin tuples behave the same.)
+ self.data = inittuple.data[:]
+ else:
+ # the same applies here; (t is tuple(t)) == 1
+ self.data = tuple(inittuple)
+ def __repr__(self): return repr(self.data)
+ def __lt__(self, other): return self.data < self.__cast(other)
+ def __le__(self, other): return self.data <= self.__cast(other)
+ def __eq__(self, other): return self.data == self.__cast(other)
+ def __ne__(self, other): return self.data != self.__cast(other)
+ def __gt__(self, other): return self.data > self.__cast(other)
+ def __ge__(self, other): return self.data >= self.__cast(other)
+ def __cast(self, other):
+ if isinstance(other, UserTuple): return other.data
+ else: return other
+ def __cmp__(self, other):
+ return cmp(self.data, self.__cast(other))
+ def __contains__(self, item): return item in self.data
+ def __len__(self): return len(self.data)
+ def __getitem__(self, i): return self.data[i]
+ def __getslice__(self, i, j):
+ i = max(i, 0); j = max(j, 0)
+ return self.__class__(self.data[i:j])
+ def __add__(self, other):
+ if isinstance(other, UserTuple):
+ return self.__class__(self.data + other.data)
+ elif isinstance(other, type(self.data)):
+ return self.__class__(self.data + other)
+ else:
+ return self.__class__(self.data + tuple(other))
+ # dir( () ) contains no __radd__ (at least in Python 2.2)
+ def __mul__(self, n):
+ return self.__class__(self.data*n)
+ __rmul__ = __mul__
+
--- /dev/null
+# Copyright (c) 2003, The Regents of the University of California,
+# through Lawrence Berkeley National Laboratory (subject to receipt of
+# any required approvals from the U.S. Dept. of Energy). All rights
+# reserved.
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+
+ident = "$Id$"
+
+import sys, types, httplib, urllib, socket, weakref
+from os.path import isfile
+from string import join, strip, split
+from UserDict import UserDict
+from cStringIO import StringIO
+from TimeoutSocket import TimeoutSocket, TimeoutError
+from urlparse import urlparse
+from httplib import HTTPConnection, HTTPSConnection
+from exceptions import Exception
+try:
+ from ZSI import _get_idstr
+except:
+ def _get_idstr(pyobj):
+ '''Python 2.3.x generates a FutureWarning for negative IDs, so
+ we use a different prefix character to ensure uniqueness, and
+ call abs() to avoid the warning.'''
+ x = id(pyobj)
+ if x < 0:
+ return 'x%x' % abs(x)
+ return 'o%x' % x
+
+import xml.dom.minidom
+from xml.dom import Node
+
+import logging
+from c14n import Canonicalize
+from Namespaces import SCHEMA, SOAP, XMLNS, ZSI_SCHEMA_URI
+
+
+try:
+ from xml.dom.ext import SplitQName
+except:
+ def SplitQName(qname):
+ '''SplitQName(qname) -> (string, string)
+
+ Split Qualified Name into a tuple of len 2, consisting
+ of the prefix and the local name.
+
+ (prefix, localName)
+
+ Special Cases:
+ xmlns -- (localName, 'xmlns')
+ None -- (None, localName)
+ '''
+
+ l = qname.split(':')
+ if len(l) == 1:
+ l.insert(0, None)
+ elif len(l) == 2:
+ if l[0] == 'xmlns':
+ l.reverse()
+ else:
+ return
+ return tuple(l)
+
+#
+# python2.3 urllib.basejoin does not remove current directory ./
+# from path and this causes problems on subsequent basejoins.
+#
+basejoin = urllib.basejoin
+if sys.version_info[0:2] < (2, 4, 0, 'final', 0)[0:2]:
+ #basejoin = lambda base,url: urllib.basejoin(base,url.lstrip('./'))
+ token = './'
+ def basejoin(base, url):
+ if url.startswith(token) is True:
+ return urllib.basejoin(base,url[2:])
+ return urllib.basejoin(base,url)
+
+class NamespaceError(Exception):
+ """Used to indicate a Namespace Error."""
+
+
+class RecursionError(Exception):
+ """Used to indicate a HTTP redirect recursion."""
+
+
+class ParseError(Exception):
+ """Used to indicate a XML parsing error."""
+
+
+class DOMException(Exception):
+ """Used to indicate a problem processing DOM."""
+
+
+class Base:
+ """Base class for instance level Logging"""
+ def __init__(self, module=__name__):
+ self.logger = logging.getLogger('%s-%s(%s)' %(module, self.__class__, _get_idstr(self)))
+
+
+class HTTPResponse:
+ """Captures the information in an HTTP response message."""
+
+ def __init__(self, response):
+ self.status = response.status
+ self.reason = response.reason
+ self.headers = response.msg
+ self.body = response.read() or None
+ response.close()
+
+class TimeoutHTTP(HTTPConnection):
+ """A custom http connection object that supports socket timeout."""
+ def __init__(self, host, port=None, timeout=20):
+ HTTPConnection.__init__(self, host, port)
+ self.timeout = timeout
+
+ def connect(self):
+ self.sock = TimeoutSocket(self.timeout)
+ self.sock.connect((self.host, self.port))
+
+
+class TimeoutHTTPS(HTTPSConnection):
+ """A custom https object that supports socket timeout. Note that this
+ is not really complete. The builtin SSL support in the Python socket
+ module requires a real socket (type) to be passed in to be hooked to
+ SSL. That means our fake socket won't work and our timeout hacks are
+ bypassed for send and recv calls. Since our hack _is_ in place at
+ connect() time, it should at least provide some timeout protection."""
+ def __init__(self, host, port=None, timeout=20, **kwargs):
+ HTTPSConnection.__init__(self, str(host), port, **kwargs)
+ self.timeout = timeout
+
+ def connect(self):
+ sock = TimeoutSocket(self.timeout)
+ sock.connect((self.host, self.port))
+ realsock = getattr(sock.sock, '_sock', sock.sock)
+ ssl = socket.ssl(realsock, self.key_file, self.cert_file)
+ self.sock = httplib.FakeSocket(sock, ssl)
+
+
+def urlopen(url, timeout=20, redirects=None):
+ """A minimal urlopen replacement hack that supports timeouts for http.
+ Note that this supports GET only."""
+ scheme, host, path, params, query, frag = urlparse(url)
+
+ if not scheme in ('http', 'https'):
+ return urllib.urlopen(url)
+ if params: path = '%s;%s' % (path, params)
+ if query: path = '%s?%s' % (path, query)
+ if frag: path = '%s#%s' % (path, frag)
+
+ if scheme == 'https':
+ # If ssl is not compiled into Python, you will not get an exception
+ # until a conn.endheaders() call. We need to know sooner, so use
+ # getattr.
+ try:
+ import M2Crypto
+ except ImportError:
+ if not hasattr(socket, 'ssl'):
+ raise RuntimeError, 'no built-in SSL Support'
+
+ conn = TimeoutHTTPS(host, None, timeout)
+ else:
+ ctx = M2Crypto.SSL.Context()
+ ctx.set_session_timeout(timeout)
+ conn = M2Crypto.httpslib.HTTPSConnection(host, ssl_context=ctx)
+ conn.set_debuglevel(1)
+
+ else:
+ conn = TimeoutHTTP(host, None, timeout)
+
+ conn.putrequest('GET', path)
+ conn.putheader('Connection', 'close')
+ conn.endheaders()
+ response = None
+ while 1:
+ response = conn.getresponse()
+ if response.status != 100:
+ break
+ conn._HTTPConnection__state = httplib._CS_REQ_SENT
+ conn._HTTPConnection__response = None
+
+ status = response.status
+
+ # If we get an HTTP redirect, we will follow it automatically.
+ if status >= 300 and status < 400:
+ location = response.msg.getheader('location')
+ if location is not None:
+ response.close()
+ if redirects is not None and redirects.has_key(location):
+ raise RecursionError(
+ 'Circular HTTP redirection detected.'
+ )
+ if redirects is None:
+ redirects = {}
+ redirects[location] = 1
+ return urlopen(location, timeout, redirects)
+ raise HTTPResponse(response)
+
+ if not (status >= 200 and status < 300):
+ raise HTTPResponse(response)
+
+ body = StringIO(response.read())
+ response.close()
+ return body
+
+class DOM:
+ """The DOM singleton defines a number of XML related constants and
+ provides a number of utility methods for DOM related tasks. It
+ also provides some basic abstractions so that the rest of the
+ package need not care about actual DOM implementation in use."""
+
+ # Namespace stuff related to the SOAP specification.
+
+ NS_SOAP_ENV_1_1 = 'http://schemas.xmlsoap.org/soap/envelope/'
+ NS_SOAP_ENC_1_1 = 'http://schemas.xmlsoap.org/soap/encoding/'
+
+ NS_SOAP_ENV_1_2 = 'http://www.w3.org/2001/06/soap-envelope'
+ NS_SOAP_ENC_1_2 = 'http://www.w3.org/2001/06/soap-encoding'
+
+ NS_SOAP_ENV_ALL = (NS_SOAP_ENV_1_1, NS_SOAP_ENV_1_2)
+ NS_SOAP_ENC_ALL = (NS_SOAP_ENC_1_1, NS_SOAP_ENC_1_2)
+
+ NS_SOAP_ENV = NS_SOAP_ENV_1_1
+ NS_SOAP_ENC = NS_SOAP_ENC_1_1
+
+ _soap_uri_mapping = {
+ NS_SOAP_ENV_1_1 : '1.1',
+ NS_SOAP_ENV_1_2 : '1.2',
+ }
+
+ SOAP_ACTOR_NEXT_1_1 = 'http://schemas.xmlsoap.org/soap/actor/next'
+ SOAP_ACTOR_NEXT_1_2 = 'http://www.w3.org/2001/06/soap-envelope/actor/next'
+ SOAP_ACTOR_NEXT_ALL = (SOAP_ACTOR_NEXT_1_1, SOAP_ACTOR_NEXT_1_2)
+
+ def SOAPUriToVersion(self, uri):
+ """Return the SOAP version related to an envelope uri."""
+ value = self._soap_uri_mapping.get(uri)
+ if value is not None:
+ return value
+ raise ValueError(
+ 'Unsupported SOAP envelope uri: %s' % uri
+ )
+
+ def GetSOAPEnvUri(self, version):
+ """Return the appropriate SOAP envelope uri for a given
+ human-friendly SOAP version string (e.g. '1.1')."""
+ attrname = 'NS_SOAP_ENV_%s' % join(split(version, '.'), '_')
+ value = getattr(self, attrname, None)
+ if value is not None:
+ return value
+ raise ValueError(
+ 'Unsupported SOAP version: %s' % version
+ )
+
+ def GetSOAPEncUri(self, version):
+ """Return the appropriate SOAP encoding uri for a given
+ human-friendly SOAP version string (e.g. '1.1')."""
+ attrname = 'NS_SOAP_ENC_%s' % join(split(version, '.'), '_')
+ value = getattr(self, attrname, None)
+ if value is not None:
+ return value
+ raise ValueError(
+ 'Unsupported SOAP version: %s' % version
+ )
+
+ def GetSOAPActorNextUri(self, version):
+ """Return the right special next-actor uri for a given
+ human-friendly SOAP version string (e.g. '1.1')."""
+ attrname = 'SOAP_ACTOR_NEXT_%s' % join(split(version, '.'), '_')
+ value = getattr(self, attrname, None)
+ if value is not None:
+ return value
+ raise ValueError(
+ 'Unsupported SOAP version: %s' % version
+ )
+
+
+ # Namespace stuff related to XML Schema.
+
+ NS_XSD_99 = 'http://www.w3.org/1999/XMLSchema'
+ NS_XSI_99 = 'http://www.w3.org/1999/XMLSchema-instance'
+
+ NS_XSD_00 = 'http://www.w3.org/2000/10/XMLSchema'
+ NS_XSI_00 = 'http://www.w3.org/2000/10/XMLSchema-instance'
+
+ NS_XSD_01 = 'http://www.w3.org/2001/XMLSchema'
+ NS_XSI_01 = 'http://www.w3.org/2001/XMLSchema-instance'
+
+ NS_XSD_ALL = (NS_XSD_99, NS_XSD_00, NS_XSD_01)
+ NS_XSI_ALL = (NS_XSI_99, NS_XSI_00, NS_XSI_01)
+
+ NS_XSD = NS_XSD_01
+ NS_XSI = NS_XSI_01
+
+ _xsd_uri_mapping = {
+ NS_XSD_99 : NS_XSI_99,
+ NS_XSD_00 : NS_XSI_00,
+ NS_XSD_01 : NS_XSI_01,
+ }
+
+ for key, value in _xsd_uri_mapping.items():
+ _xsd_uri_mapping[value] = key
+
+
+ def InstanceUriForSchemaUri(self, uri):
+ """Return the appropriate matching XML Schema instance uri for
+ the given XML Schema namespace uri."""
+ return self._xsd_uri_mapping.get(uri)
+
+ def SchemaUriForInstanceUri(self, uri):
+ """Return the appropriate matching XML Schema namespace uri for
+ the given XML Schema instance namespace uri."""
+ return self._xsd_uri_mapping.get(uri)
+
+
+ # Namespace stuff related to WSDL.
+
+ NS_WSDL_1_1 = 'http://schemas.xmlsoap.org/wsdl/'
+ NS_WSDL_ALL = (NS_WSDL_1_1,)
+ NS_WSDL = NS_WSDL_1_1
+
+ NS_SOAP_BINDING_1_1 = 'http://schemas.xmlsoap.org/wsdl/soap/'
+ NS_HTTP_BINDING_1_1 = 'http://schemas.xmlsoap.org/wsdl/http/'
+ NS_MIME_BINDING_1_1 = 'http://schemas.xmlsoap.org/wsdl/mime/'
+
+ NS_SOAP_BINDING_ALL = (NS_SOAP_BINDING_1_1,)
+ NS_HTTP_BINDING_ALL = (NS_HTTP_BINDING_1_1,)
+ NS_MIME_BINDING_ALL = (NS_MIME_BINDING_1_1,)
+
+ NS_SOAP_BINDING = NS_SOAP_BINDING_1_1
+ NS_HTTP_BINDING = NS_HTTP_BINDING_1_1
+ NS_MIME_BINDING = NS_MIME_BINDING_1_1
+
+ NS_SOAP_HTTP_1_1 = 'http://schemas.xmlsoap.org/soap/http'
+ NS_SOAP_HTTP_ALL = (NS_SOAP_HTTP_1_1,)
+ NS_SOAP_HTTP = NS_SOAP_HTTP_1_1
+
+
+ _wsdl_uri_mapping = {
+ NS_WSDL_1_1 : '1.1',
+ }
+
+ def WSDLUriToVersion(self, uri):
+ """Return the WSDL version related to a WSDL namespace uri."""
+ value = self._wsdl_uri_mapping.get(uri)
+ if value is not None:
+ return value
+ raise ValueError(
+ 'Unsupported SOAP envelope uri: %s' % uri
+ )
+
+ def GetWSDLUri(self, version):
+ attr = 'NS_WSDL_%s' % join(split(version, '.'), '_')
+ value = getattr(self, attr, None)
+ if value is not None:
+ return value
+ raise ValueError(
+ 'Unsupported WSDL version: %s' % version
+ )
+
+ def GetWSDLSoapBindingUri(self, version):
+ attr = 'NS_SOAP_BINDING_%s' % join(split(version, '.'), '_')
+ value = getattr(self, attr, None)
+ if value is not None:
+ return value
+ raise ValueError(
+ 'Unsupported WSDL version: %s' % version
+ )
+
+ def GetWSDLHttpBindingUri(self, version):
+ attr = 'NS_HTTP_BINDING_%s' % join(split(version, '.'), '_')
+ value = getattr(self, attr, None)
+ if value is not None:
+ return value
+ raise ValueError(
+ 'Unsupported WSDL version: %s' % version
+ )
+
+ def GetWSDLMimeBindingUri(self, version):
+ attr = 'NS_MIME_BINDING_%s' % join(split(version, '.'), '_')
+ value = getattr(self, attr, None)
+ if value is not None:
+ return value
+ raise ValueError(
+ 'Unsupported WSDL version: %s' % version
+ )
+
+ def GetWSDLHttpTransportUri(self, version):
+ attr = 'NS_SOAP_HTTP_%s' % join(split(version, '.'), '_')
+ value = getattr(self, attr, None)
+ if value is not None:
+ return value
+ raise ValueError(
+ 'Unsupported WSDL version: %s' % version
+ )
+
+
+ # Other xml namespace constants.
+ NS_XMLNS = 'http://www.w3.org/2000/xmlns/'
+
+
+
+ def isElement(self, node, name, nsuri=None):
+ """Return true if the given node is an element with the given
+ name and optional namespace uri."""
+ if node.nodeType != node.ELEMENT_NODE:
+ return 0
+ return node.localName == name and \
+ (nsuri is None or self.nsUriMatch(node.namespaceURI, nsuri))
+
+ def getElement(self, node, name, nsuri=None, default=join):
+ """Return the first child of node with a matching name and
+ namespace uri, or the default if one is provided."""
+ nsmatch = self.nsUriMatch
+ ELEMENT_NODE = node.ELEMENT_NODE
+ for child in node.childNodes:
+ if child.nodeType == ELEMENT_NODE:
+ if ((child.localName == name or name is None) and
+ (nsuri is None or nsmatch(child.namespaceURI, nsuri))
+ ):
+ return child
+ if default is not join:
+ return default
+ raise KeyError, name
+
+ def getElementById(self, node, id, default=join):
+ """Return the first child of node matching an id reference."""
+ attrget = self.getAttr
+ ELEMENT_NODE = node.ELEMENT_NODE
+ for child in node.childNodes:
+ if child.nodeType == ELEMENT_NODE:
+ if attrget(child, 'id') == id:
+ return child
+ if default is not join:
+ return default
+ raise KeyError, name
+
+ def getMappingById(self, document, depth=None, element=None,
+ mapping=None, level=1):
+ """Create an id -> element mapping of those elements within a
+ document that define an id attribute. The depth of the search
+ may be controlled by using the (1-based) depth argument."""
+ if document is not None:
+ element = document.documentElement
+ mapping = {}
+ attr = element._attrs.get('id', None)
+ if attr is not None:
+ mapping[attr.value] = element
+ if depth is None or depth > level:
+ level = level + 1
+ ELEMENT_NODE = element.ELEMENT_NODE
+ for child in element.childNodes:
+ if child.nodeType == ELEMENT_NODE:
+ self.getMappingById(None, depth, child, mapping, level)
+ return mapping
+
+ def getElements(self, node, name, nsuri=None):
+ """Return a sequence of the child elements of the given node that
+ match the given name and optional namespace uri."""
+ nsmatch = self.nsUriMatch
+ result = []
+ ELEMENT_NODE = node.ELEMENT_NODE
+ for child in node.childNodes:
+ if child.nodeType == ELEMENT_NODE:
+ if ((child.localName == name or name is None) and (
+ (nsuri is None) or nsmatch(child.namespaceURI, nsuri))):
+ result.append(child)
+ return result
+
+ def hasAttr(self, node, name, nsuri=None):
+ """Return true if element has attribute with the given name and
+ optional nsuri. If nsuri is not specified, returns true if an
+ attribute exists with the given name with any namespace."""
+ if nsuri is None:
+ if node.hasAttribute(name):
+ return True
+ return False
+ return node.hasAttributeNS(nsuri, name)
+
+ def getAttr(self, node, name, nsuri=None, default=join):
+ """Return the value of the attribute named 'name' with the
+ optional nsuri, or the default if one is specified. If
+ nsuri is not specified, an attribute that matches the
+ given name will be returned regardless of namespace."""
+ if nsuri is None:
+ result = node._attrs.get(name, None)
+ if result is None:
+ for item in node._attrsNS.keys():
+ if item[1] == name:
+ result = node._attrsNS[item]
+ break
+ else:
+ result = node._attrsNS.get((nsuri, name), None)
+ if result is not None:
+ return result.value
+ if default is not join:
+ return default
+ return ''
+
+ def getAttrs(self, node):
+ """Return a Collection of all attributes
+ """
+ attrs = {}
+ for k,v in node._attrs.items():
+ attrs[k] = v.value
+ return attrs
+
+ def getElementText(self, node, preserve_ws=None):
+ """Return the text value of an xml element node. Leading and trailing
+ whitespace is stripped from the value unless the preserve_ws flag
+ is passed with a true value."""
+ result = []
+ for child in node.childNodes:
+ nodetype = child.nodeType
+ if nodetype == child.TEXT_NODE or \
+ nodetype == child.CDATA_SECTION_NODE:
+ result.append(child.nodeValue)
+ value = join(result, '')
+ if preserve_ws is None:
+ value = strip(value)
+ return value
+
+ def findNamespaceURI(self, prefix, node):
+ """Find a namespace uri given a prefix and a context node."""
+ attrkey = (self.NS_XMLNS, prefix)
+ DOCUMENT_NODE = node.DOCUMENT_NODE
+ ELEMENT_NODE = node.ELEMENT_NODE
+ while 1:
+ if node is None:
+ raise DOMException('Value for prefix %s not found.' % prefix)
+ if node.nodeType != ELEMENT_NODE:
+ node = node.parentNode
+ continue
+ result = node._attrsNS.get(attrkey, None)
+ if result is not None:
+ return result.value
+ if hasattr(node, '__imported__'):
+ raise DOMException('Value for prefix %s not found.' % prefix)
+ node = node.parentNode
+ if node.nodeType == DOCUMENT_NODE:
+ raise DOMException('Value for prefix %s not found.' % prefix)
+
+ def findDefaultNS(self, node):
+ """Return the current default namespace uri for the given node."""
+ attrkey = (self.NS_XMLNS, 'xmlns')
+ DOCUMENT_NODE = node.DOCUMENT_NODE
+ ELEMENT_NODE = node.ELEMENT_NODE
+ while 1:
+ if node.nodeType != ELEMENT_NODE:
+ node = node.parentNode
+ continue
+ result = node._attrsNS.get(attrkey, None)
+ if result is not None:
+ return result.value
+ if hasattr(node, '__imported__'):
+ raise DOMException('Cannot determine default namespace.')
+ node = node.parentNode
+ if node.nodeType == DOCUMENT_NODE:
+ raise DOMException('Cannot determine default namespace.')
+
+ def findTargetNS(self, node):
+ """Return the defined target namespace uri for the given node."""
+ attrget = self.getAttr
+ attrkey = (self.NS_XMLNS, 'xmlns')
+ DOCUMENT_NODE = node.DOCUMENT_NODE
+ ELEMENT_NODE = node.ELEMENT_NODE
+ while 1:
+ if node.nodeType != ELEMENT_NODE:
+ node = node.parentNode
+ continue
+ result = attrget(node, 'targetNamespace', default=None)
+ if result is not None:
+ return result
+ node = node.parentNode
+ if node.nodeType == DOCUMENT_NODE:
+ raise DOMException('Cannot determine target namespace.')
+
+ def getTypeRef(self, element):
+ """Return (namespaceURI, name) for a type attribue of the given
+ element, or None if the element does not have a type attribute."""
+ typeattr = self.getAttr(element, 'type', default=None)
+ if typeattr is None:
+ return None
+ parts = typeattr.split(':', 1)
+ if len(parts) == 2:
+ nsuri = self.findNamespaceURI(parts[0], element)
+ else:
+ nsuri = self.findDefaultNS(element)
+ return (nsuri, parts[1])
+
+ def importNode(self, document, node, deep=0):
+ """Implements (well enough for our purposes) DOM node import."""
+ nodetype = node.nodeType
+ if nodetype in (node.DOCUMENT_NODE, node.DOCUMENT_TYPE_NODE):
+ raise DOMException('Illegal node type for importNode')
+ if nodetype == node.ENTITY_REFERENCE_NODE:
+ deep = 0
+ clone = node.cloneNode(deep)
+ self._setOwnerDoc(document, clone)
+ clone.__imported__ = 1
+ return clone
+
+ def _setOwnerDoc(self, document, node):
+ node.ownerDocument = document
+ for child in node.childNodes:
+ self._setOwnerDoc(document, child)
+
+ def nsUriMatch(self, value, wanted, strict=0, tt=type(())):
+ """Return a true value if two namespace uri values match."""
+ if value == wanted or (type(wanted) is tt) and value in wanted:
+ return 1
+ if not strict and value is not None:
+ wanted = type(wanted) is tt and wanted or (wanted,)
+ value = value[-1:] != '/' and value or value[:-1]
+ for item in wanted:
+ if item == value or item[:-1] == value:
+ return 1
+ return 0
+
+ def createDocument(self, nsuri, qname, doctype=None):
+ """Create a new writable DOM document object."""
+ impl = xml.dom.minidom.getDOMImplementation()
+ return impl.createDocument(nsuri, qname, doctype)
+
+ def loadDocument(self, data):
+ """Load an xml file from a file-like object and return a DOM
+ document instance."""
+ return xml.dom.minidom.parse(data)
+
+ def loadFromURL(self, url):
+ """Load an xml file from a URL and return a DOM document."""
+ if isfile(url) is True:
+ file = open(url, 'r')
+ else:
+ file = urlopen(url)
+
+ try:
+ result = self.loadDocument(file)
+ except Exception, ex:
+ file.close()
+ raise ParseError(('Failed to load document %s' %url,) + ex.args)
+ else:
+ file.close()
+ return result
+
+DOM = DOM()
+
+
+class MessageInterface:
+ '''Higher Level Interface, delegates to DOM singleton, must
+ be subclassed and implement all methods that throw NotImplementedError.
+ '''
+ def __init__(self, sw):
+ '''Constructor, May be extended, do not override.
+ sw -- soapWriter instance
+ '''
+ self.sw = None
+ if type(sw) != weakref.ReferenceType and sw is not None:
+ self.sw = weakref.ref(sw)
+ else:
+ self.sw = sw
+
+ def AddCallback(self, func, *arglist):
+ self.sw().AddCallback(func, *arglist)
+
+ def Known(self, obj):
+ return self.sw().Known(obj)
+
+ def Forget(self, obj):
+ return self.sw().Forget(obj)
+
+ def canonicalize(self):
+ '''canonicalize the underlying DOM, and return as string.
+ '''
+ raise NotImplementedError, ''
+
+ def createDocument(self, namespaceURI=SOAP.ENV, localName='Envelope'):
+ '''create Document
+ '''
+ raise NotImplementedError, ''
+
+ def createAppendElement(self, namespaceURI, localName):
+ '''create and append element(namespaceURI,localName), and return
+ the node.
+ '''
+ raise NotImplementedError, ''
+
+ def findNamespaceURI(self, qualifiedName):
+ raise NotImplementedError, ''
+
+ def resolvePrefix(self, prefix):
+ raise NotImplementedError, ''
+
+ def setAttributeNS(self, namespaceURI, localName, value):
+ '''set attribute (namespaceURI, localName)=value
+ '''
+ raise NotImplementedError, ''
+
+ def setAttributeType(self, namespaceURI, localName):
+ '''set attribute xsi:type=(namespaceURI, localName)
+ '''
+ raise NotImplementedError, ''
+
+ def setNamespaceAttribute(self, namespaceURI, prefix):
+ '''set namespace attribute xmlns:prefix=namespaceURI
+ '''
+ raise NotImplementedError, ''
+
+
+class ElementProxy(Base, MessageInterface):
+ '''
+ '''
+ _soap_env_prefix = 'SOAP-ENV'
+ _soap_enc_prefix = 'SOAP-ENC'
+ _zsi_prefix = 'ZSI'
+ _xsd_prefix = 'xsd'
+ _xsi_prefix = 'xsi'
+ _xml_prefix = 'xml'
+ _xmlns_prefix = 'xmlns'
+
+ _soap_env_nsuri = SOAP.ENV
+ _soap_enc_nsuri = SOAP.ENC
+ _zsi_nsuri = ZSI_SCHEMA_URI
+ _xsd_nsuri = SCHEMA.XSD3
+ _xsi_nsuri = SCHEMA.XSI3
+ _xml_nsuri = XMLNS.XML
+ _xmlns_nsuri = XMLNS.BASE
+
+ standard_ns = {\
+ _xml_prefix:_xml_nsuri,
+ _xmlns_prefix:_xmlns_nsuri
+ }
+ reserved_ns = {\
+ _soap_env_prefix:_soap_env_nsuri,
+ _soap_enc_prefix:_soap_enc_nsuri,
+ _zsi_prefix:_zsi_nsuri,
+ _xsd_prefix:_xsd_nsuri,
+ _xsi_prefix:_xsi_nsuri,
+ }
+ name = None
+ namespaceURI = None
+
+ def __init__(self, sw, message=None):
+ '''Initialize.
+ sw -- SoapWriter
+ '''
+ self._indx = 0
+ MessageInterface.__init__(self, sw)
+ Base.__init__(self)
+ self._dom = DOM
+ self.node = None
+ if type(message) in (types.StringType,types.UnicodeType):
+ self.loadFromString(message)
+ elif isinstance(message, ElementProxy):
+ self.node = message._getNode()
+ else:
+ self.node = message
+ self.processorNss = self.standard_ns.copy()
+ self.processorNss.update(self.reserved_ns)
+
+ def __str__(self):
+ return self.toString()
+
+ def evaluate(self, expression, processorNss=None):
+ '''expression -- XPath compiled expression
+ '''
+ from Ft.Xml import XPath
+ if not processorNss:
+ context = XPath.Context.Context(self.node, processorNss=self.processorNss)
+ else:
+ context = XPath.Context.Context(self.node, processorNss=processorNss)
+ nodes = expression.evaluate(context)
+ return map(lambda node: ElementProxy(self.sw,node), nodes)
+
+ #############################################
+ # Methods for checking/setting the
+ # classes (namespaceURI,name) node.
+ #############################################
+ def checkNode(self, namespaceURI=None, localName=None):
+ '''
+ namespaceURI -- namespace of element
+ localName -- local name of element
+ '''
+ namespaceURI = namespaceURI or self.namespaceURI
+ localName = localName or self.name
+ check = False
+ if localName and self.node:
+ check = self._dom.isElement(self.node, localName, namespaceURI)
+ if not check:
+ raise NamespaceError, 'unexpected node type %s, expecting %s' %(self.node, localName)
+
+ def setNode(self, node=None):
+ if node:
+ if isinstance(node, ElementProxy):
+ self.node = node._getNode()
+ else:
+ self.node = node
+ elif self.node:
+ node = self._dom.getElement(self.node, self.name, self.namespaceURI, default=None)
+ if not node:
+ raise NamespaceError, 'cant find element (%s,%s)' %(self.namespaceURI,self.name)
+ self.node = node
+ else:
+ #self.node = self._dom.create(self.node, self.name, self.namespaceURI, default=None)
+ self.createDocument(self.namespaceURI, localName=self.name, doctype=None)
+
+ self.checkNode()
+
+ #############################################
+ # Wrapper Methods for direct DOM Element Node access
+ #############################################
+ def _getNode(self):
+ return self.node
+
+ def _getElements(self):
+ return self._dom.getElements(self.node, name=None)
+
+ def _getOwnerDocument(self):
+ return self.node.ownerDocument or self.node
+
+ def _getUniquePrefix(self):
+ '''I guess we need to resolve all potential prefixes
+ because when the current node is attached it copies the
+ namespaces into the parent node.
+ '''
+ while 1:
+ self._indx += 1
+ prefix = 'ns%d' %self._indx
+ try:
+ self._dom.findNamespaceURI(prefix, self._getNode())
+ except DOMException, ex:
+ break
+ return prefix
+
+ def _getPrefix(self, node, nsuri):
+ '''
+ Keyword arguments:
+ node -- DOM Element Node
+ nsuri -- namespace of attribute value
+ '''
+ try:
+ if node and (node.nodeType == node.ELEMENT_NODE) and \
+ (nsuri == self._dom.findDefaultNS(node)):
+ return None
+ except DOMException, ex:
+ pass
+ if nsuri == XMLNS.XML:
+ return self._xml_prefix
+ if node.nodeType == Node.ELEMENT_NODE:
+ for attr in node.attributes.values():
+ if attr.namespaceURI == XMLNS.BASE \
+ and nsuri == attr.value:
+ return attr.localName
+ else:
+ if node.parentNode:
+ return self._getPrefix(node.parentNode, nsuri)
+ raise NamespaceError, 'namespaceURI "%s" is not defined' %nsuri
+
+ def _appendChild(self, node):
+ '''
+ Keyword arguments:
+ node -- DOM Element Node
+ '''
+ if node is None:
+ raise TypeError, 'node is None'
+ self.node.appendChild(node)
+
+ def _insertBefore(self, newChild, refChild):
+ '''
+ Keyword arguments:
+ child -- DOM Element Node to insert
+ refChild -- DOM Element Node
+ '''
+ self.node.insertBefore(newChild, refChild)
+
+ def _setAttributeNS(self, namespaceURI, qualifiedName, value):
+ '''
+ Keyword arguments:
+ namespaceURI -- namespace of attribute
+ qualifiedName -- qualified name of new attribute value
+ value -- value of attribute
+ '''
+ self.node.setAttributeNS(namespaceURI, qualifiedName, value)
+
+ #############################################
+ #General Methods
+ #############################################
+ def isFault(self):
+ '''check to see if this is a soap:fault message.
+ '''
+ return False
+
+ def getPrefix(self, namespaceURI):
+ try:
+ prefix = self._getPrefix(node=self.node, nsuri=namespaceURI)
+ except NamespaceError, ex:
+ prefix = self._getUniquePrefix()
+ self.setNamespaceAttribute(prefix, namespaceURI)
+ return prefix
+
+ def getDocument(self):
+ return self._getOwnerDocument()
+
+ def setDocument(self, document):
+ self.node = document
+
+ def importFromString(self, xmlString):
+ doc = self._dom.loadDocument(StringIO(xmlString))
+ node = self._dom.getElement(doc, name=None)
+ clone = self.importNode(node)
+ self._appendChild(clone)
+
+ def importNode(self, node):
+ if isinstance(node, ElementProxy):
+ node = node._getNode()
+ return self._dom.importNode(self._getOwnerDocument(), node, deep=1)
+
+ def loadFromString(self, data):
+ self.node = self._dom.loadDocument(StringIO(data))
+
+ def canonicalize(self):
+ return Canonicalize(self.node)
+
+ def toString(self):
+ return self.canonicalize()
+
+ def createDocument(self, namespaceURI, localName, doctype=None):
+ '''If specified must be a SOAP envelope, else may contruct an empty document.
+ '''
+ prefix = self._soap_env_prefix
+
+ if namespaceURI == self.reserved_ns[prefix]:
+ qualifiedName = '%s:%s' %(prefix,localName)
+ elif namespaceURI is localName is None:
+ self.node = self._dom.createDocument(None,None,None)
+ return
+ else:
+ raise KeyError, 'only support creation of document in %s' %self.reserved_ns[prefix]
+
+ document = self._dom.createDocument(nsuri=namespaceURI, qname=qualifiedName, doctype=doctype)
+ self.node = document.childNodes[0]
+
+ #set up reserved namespace attributes
+ for prefix,nsuri in self.reserved_ns.items():
+ self._setAttributeNS(namespaceURI=self._xmlns_nsuri,
+ qualifiedName='%s:%s' %(self._xmlns_prefix,prefix),
+ value=nsuri)
+
+ #############################################
+ #Methods for attributes
+ #############################################
+ def hasAttribute(self, namespaceURI, localName):
+ return self._dom.hasAttr(self._getNode(), name=localName, nsuri=namespaceURI)
+
+ def setAttributeType(self, namespaceURI, localName):
+ '''set xsi:type
+ Keyword arguments:
+ namespaceURI -- namespace of attribute value
+ localName -- name of new attribute value
+
+ '''
+ self.logger.debug('setAttributeType: (%s,%s)', namespaceURI, localName)
+ value = localName
+ if namespaceURI:
+ value = '%s:%s' %(self.getPrefix(namespaceURI),localName)
+
+ xsi_prefix = self.getPrefix(self._xsi_nsuri)
+ self._setAttributeNS(self._xsi_nsuri, '%s:type' %xsi_prefix, value)
+
+ def createAttributeNS(self, namespace, name, value):
+ document = self._getOwnerDocument()
+ ##this function doesn't exist!! it has only two arguments
+ attrNode = document.createAttributeNS(namespace, name, value)
+
+ def setAttributeNS(self, namespaceURI, localName, value):
+ '''
+ Keyword arguments:
+ namespaceURI -- namespace of attribute to create, None is for
+ attributes in no namespace.
+ localName -- local name of new attribute
+ value -- value of new attribute
+ '''
+ prefix = None
+ if namespaceURI:
+ try:
+ prefix = self.getPrefix(namespaceURI)
+ except KeyError, ex:
+ prefix = 'ns2'
+ self.setNamespaceAttribute(prefix, namespaceURI)
+ qualifiedName = localName
+ if prefix:
+ qualifiedName = '%s:%s' %(prefix, localName)
+ self._setAttributeNS(namespaceURI, qualifiedName, value)
+
+ def setNamespaceAttribute(self, prefix, namespaceURI):
+ '''
+ Keyword arguments:
+ prefix -- xmlns prefix
+ namespaceURI -- value of prefix
+ '''
+ self._setAttributeNS(XMLNS.BASE, 'xmlns:%s' %prefix, namespaceURI)
+
+ #############################################
+ #Methods for elements
+ #############################################
+ def createElementNS(self, namespace, qname):
+ '''
+ Keyword arguments:
+ namespace -- namespace of element to create
+ qname -- qualified name of new element
+ '''
+ document = self._getOwnerDocument()
+ node = document.createElementNS(namespace, qname)
+ return ElementProxy(self.sw, node)
+
+ def createAppendSetElement(self, namespaceURI, localName, prefix=None):
+ '''Create a new element (namespaceURI,name), append it
+ to current node, then set it to be the current node.
+ Keyword arguments:
+ namespaceURI -- namespace of element to create
+ localName -- local name of new element
+ prefix -- if namespaceURI is not defined, declare prefix. defaults
+ to 'ns1' if left unspecified.
+ '''
+ node = self.createAppendElement(namespaceURI, localName, prefix=None)
+ node=node._getNode()
+ self._setNode(node._getNode())
+
+ def createAppendElement(self, namespaceURI, localName, prefix=None):
+ '''Create a new element (namespaceURI,name), append it
+ to current node, and return the newly created node.
+ Keyword arguments:
+ namespaceURI -- namespace of element to create
+ localName -- local name of new element
+ prefix -- if namespaceURI is not defined, declare prefix. defaults
+ to 'ns1' if left unspecified.
+ '''
+ declare = False
+ qualifiedName = localName
+ if namespaceURI:
+ try:
+ prefix = self.getPrefix(namespaceURI)
+ except:
+ declare = True
+ prefix = prefix or self._getUniquePrefix()
+ if prefix:
+ qualifiedName = '%s:%s' %(prefix, localName)
+ node = self.createElementNS(namespaceURI, qualifiedName)
+ if declare:
+ node._setAttributeNS(XMLNS.BASE, 'xmlns:%s' %prefix, namespaceURI)
+ self._appendChild(node=node._getNode())
+ return node
+
+ def createInsertBefore(self, namespaceURI, localName, refChild):
+ qualifiedName = localName
+ prefix = self.getPrefix(namespaceURI)
+ if prefix:
+ qualifiedName = '%s:%s' %(prefix, localName)
+ node = self.createElementNS(namespaceURI, qualifiedName)
+ self._insertBefore(newChild=node._getNode(), refChild=refChild._getNode())
+ return node
+
+ def getElement(self, namespaceURI, localName):
+ '''
+ Keyword arguments:
+ namespaceURI -- namespace of element
+ localName -- local name of element
+ '''
+ node = self._dom.getElement(self.node, localName, namespaceURI, default=None)
+ if node:
+ return ElementProxy(self.sw, node)
+ return None
+
+ def getAttributeValue(self, namespaceURI, localName):
+ '''
+ Keyword arguments:
+ namespaceURI -- namespace of attribute
+ localName -- local name of attribute
+ '''
+ if self.hasAttribute(namespaceURI, localName):
+ attr = self.node.getAttributeNodeNS(namespaceURI,localName)
+ return attr.value
+ return None
+
+ def getValue(self):
+ return self._dom.getElementText(self.node, preserve_ws=True)
+
+ #############################################
+ #Methods for text nodes
+ #############################################
+ def createAppendTextNode(self, pyobj):
+ node = self.createTextNode(pyobj)
+ self._appendChild(node=node._getNode())
+ return node
+
+ def createTextNode(self, pyobj):
+ document = self._getOwnerDocument()
+ node = document.createTextNode(pyobj)
+ return ElementProxy(self.sw, node)
+
+ #############################################
+ #Methods for retrieving namespaceURI's
+ #############################################
+ def findNamespaceURI(self, qualifiedName):
+ parts = SplitQName(qualifiedName)
+ element = self._getNode()
+ if len(parts) == 1:
+ return (self._dom.findTargetNS(element), value)
+ return self._dom.findNamespaceURI(parts[0], element)
+
+ def resolvePrefix(self, prefix):
+ element = self._getNode()
+ return self._dom.findNamespaceURI(prefix, element)
+
+ def getSOAPEnvURI(self):
+ return self._soap_env_nsuri
+
+ def isEmpty(self):
+ return not self.node
+
+
+
+class Collection(UserDict):
+ """Helper class for maintaining ordered named collections."""
+ default = lambda self,k: k.name
+ def __init__(self, parent, key=None):
+ UserDict.__init__(self)
+ self.parent = weakref.ref(parent)
+ self.list = []
+ self._func = key or self.default
+
+ def __getitem__(self, key):
+ if type(key) is type(1):
+ return self.list[key]
+ return self.data[key]
+
+ def __setitem__(self, key, item):
+ item.parent = weakref.ref(self)
+ self.list.append(item)
+ self.data[key] = item
+
+ def keys(self):
+ return map(lambda i: self._func(i), self.list)
+
+ def items(self):
+ return map(lambda i: (self._func(i), i), self.list)
+
+ def values(self):
+ return self.list
+
+
+class CollectionNS(UserDict):
+ """Helper class for maintaining ordered named collections."""
+ default = lambda self,k: k.name
+ def __init__(self, parent, key=None):
+ UserDict.__init__(self)
+ self.parent = weakref.ref(parent)
+ self.targetNamespace = None
+ self.list = []
+ self._func = key or self.default
+
+ def __getitem__(self, key):
+ self.targetNamespace = self.parent().targetNamespace
+ if type(key) is types.IntType:
+ return self.list[key]
+ elif self.__isSequence(key):
+ nsuri,name = key
+ return self.data[nsuri][name]
+ return self.data[self.parent().targetNamespace][key]
+
+ def __setitem__(self, key, item):
+ item.parent = weakref.ref(self)
+ self.list.append(item)
+ targetNamespace = getattr(item, 'targetNamespace', self.parent().targetNamespace)
+ if not self.data.has_key(targetNamespace):
+ self.data[targetNamespace] = {}
+ self.data[targetNamespace][key] = item
+
+ def __isSequence(self, key):
+ return (type(key) in (types.TupleType,types.ListType) and len(key) == 2)
+
+ def keys(self):
+ keys = []
+ for tns in self.data.keys():
+ keys.append(map(lambda i: (tns,self._func(i)), self.data[tns].values()))
+ return keys
+
+ def items(self):
+ return map(lambda i: (self._func(i), i), self.list)
+
+ def values(self):
+ return self.list
+
+
+
+# This is a runtime guerilla patch for pulldom (used by minidom) so
+# that xml namespace declaration attributes are not lost in parsing.
+# We need them to do correct QName linking for XML Schema and WSDL.
+# The patch has been submitted to SF for the next Python version.
+
+from xml.dom.pulldom import PullDOM, START_ELEMENT
+if 1:
+ def startPrefixMapping(self, prefix, uri):
+ if not hasattr(self, '_xmlns_attrs'):
+ self._xmlns_attrs = []
+ self._xmlns_attrs.append((prefix or 'xmlns', uri))
+ self._ns_contexts.append(self._current_context.copy())
+ self._current_context[uri] = prefix or ''
+
+ PullDOM.startPrefixMapping = startPrefixMapping
+
+ def startElementNS(self, name, tagName , attrs):
+ # Retrieve xml namespace declaration attributes.
+ xmlns_uri = 'http://www.w3.org/2000/xmlns/'
+ xmlns_attrs = getattr(self, '_xmlns_attrs', None)
+ if xmlns_attrs is not None:
+ for aname, value in xmlns_attrs:
+ attrs._attrs[(xmlns_uri, aname)] = value
+ self._xmlns_attrs = []
+ uri, localname = name
+ if uri:
+ # When using namespaces, the reader may or may not
+ # provide us with the original name. If not, create
+ # *a* valid tagName from the current context.
+ if tagName is None:
+ prefix = self._current_context[uri]
+ if prefix:
+ tagName = prefix + ":" + localname
+ else:
+ tagName = localname
+ if self.document:
+ node = self.document.createElementNS(uri, tagName)
+ else:
+ node = self.buildDocument(uri, tagName)
+ else:
+ # When the tagname is not prefixed, it just appears as
+ # localname
+ if self.document:
+ node = self.document.createElement(localname)
+ else:
+ node = self.buildDocument(None, localname)
+
+ for aname,value in attrs.items():
+ a_uri, a_localname = aname
+ if a_uri == xmlns_uri:
+ if a_localname == 'xmlns':
+ qname = a_localname
+ else:
+ qname = 'xmlns:' + a_localname
+ attr = self.document.createAttributeNS(a_uri, qname)
+ node.setAttributeNodeNS(attr)
+ elif a_uri:
+ prefix = self._current_context[a_uri]
+ if prefix:
+ qname = prefix + ":" + a_localname
+ else:
+ qname = a_localname
+ attr = self.document.createAttributeNS(a_uri, qname)
+ node.setAttributeNodeNS(attr)
+ else:
+ attr = self.document.createAttribute(a_localname)
+ node.setAttributeNode(attr)
+ attr.value = value
+
+ self.lastEvent[1] = [(START_ELEMENT, node), None]
+ self.lastEvent = self.lastEvent[1]
+ self.push(node)
+
+ PullDOM.startElementNS = startElementNS
+
+#
+# This is a runtime guerilla patch for minidom so
+# that xmlns prefixed attributes dont raise AttributeErrors
+# during cloning.
+#
+# Namespace declarations can appear in any start-tag, must look for xmlns
+# prefixed attribute names during cloning.
+#
+# key (attr.namespaceURI, tag)
+# ('http://www.w3.org/2000/xmlns/', u'xsd') <xml.dom.minidom.Attr instance at 0x82227c4>
+# ('http://www.w3.org/2000/xmlns/', 'xmlns') <xml.dom.minidom.Attr instance at 0x8414b3c>
+#
+# xml.dom.minidom.Attr.nodeName = xmlns:xsd
+# xml.dom.minidom.Attr.value = = http://www.w3.org/2001/XMLSchema
+
+if 1:
+ def _clone_node(node, deep, newOwnerDocument):
+ """
+ Clone a node and give it the new owner document.
+ Called by Node.cloneNode and Document.importNode
+ """
+ if node.ownerDocument.isSameNode(newOwnerDocument):
+ operation = xml.dom.UserDataHandler.NODE_CLONED
+ else:
+ operation = xml.dom.UserDataHandler.NODE_IMPORTED
+ if node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE:
+ clone = newOwnerDocument.createElementNS(node.namespaceURI,
+ node.nodeName)
+ for attr in node.attributes.values():
+ clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)
+
+ prefix, tag = xml.dom.minidom._nssplit(attr.nodeName)
+ if prefix == 'xmlns':
+ a = clone.getAttributeNodeNS(attr.namespaceURI, tag)
+ elif prefix:
+ a = clone.getAttributeNodeNS(attr.namespaceURI, tag)
+ else:
+ a = clone.getAttributeNodeNS(attr.namespaceURI, attr.nodeName)
+ a.specified = attr.specified
+
+ if deep:
+ for child in node.childNodes:
+ c = xml.dom.minidom._clone_node(child, deep, newOwnerDocument)
+ clone.appendChild(c)
+ elif node.nodeType == xml.dom.minidom.Node.DOCUMENT_FRAGMENT_NODE:
+ clone = newOwnerDocument.createDocumentFragment()
+ if deep:
+ for child in node.childNodes:
+ c = xml.dom.minidom._clone_node(child, deep, newOwnerDocument)
+ clone.appendChild(c)
+
+ elif node.nodeType == xml.dom.minidom.Node.TEXT_NODE:
+ clone = newOwnerDocument.createTextNode(node.data)
+ elif node.nodeType == xml.dom.minidom.Node.CDATA_SECTION_NODE:
+ clone = newOwnerDocument.createCDATASection(node.data)
+ elif node.nodeType == xml.dom.minidom.Node.PROCESSING_INSTRUCTION_NODE:
+ clone = newOwnerDocument.createProcessingInstruction(node.target,
+ node.data)
+ elif node.nodeType == xml.dom.minidom.Node.COMMENT_NODE:
+ clone = newOwnerDocument.createComment(node.data)
+ elif node.nodeType == xml.dom.minidom.Node.ATTRIBUTE_NODE:
+ clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
+ node.nodeName)
+ clone.specified = True
+ clone.value = node.value
+ elif node.nodeType == xml.dom.minidom.Node.DOCUMENT_TYPE_NODE:
+ assert node.ownerDocument is not newOwnerDocument
+ operation = xml.dom.UserDataHandler.NODE_IMPORTED
+ clone = newOwnerDocument.implementation.createDocumentType(
+ node.name, node.publicId, node.systemId)
+ clone.ownerDocument = newOwnerDocument
+ if deep:
+ clone.entities._seq = []
+ clone.notations._seq = []
+ for n in node.notations._seq:
+ notation = xml.dom.minidom.Notation(n.nodeName, n.publicId, n.systemId)
+ notation.ownerDocument = newOwnerDocument
+ clone.notations._seq.append(notation)
+ if hasattr(n, '_call_user_data_handler'):
+ n._call_user_data_handler(operation, n, notation)
+ for e in node.entities._seq:
+ entity = xml.dom.minidom.Entity(e.nodeName, e.publicId, e.systemId,
+ e.notationName)
+ entity.actualEncoding = e.actualEncoding
+ entity.encoding = e.encoding
+ entity.version = e.version
+ entity.ownerDocument = newOwnerDocument
+ clone.entities._seq.append(entity)
+ if hasattr(e, '_call_user_data_handler'):
+ e._call_user_data_handler(operation, n, entity)
+ else:
+ # Note the cloning of Document and DocumentType nodes is
+ # implemenetation specific. minidom handles those cases
+ # directly in the cloneNode() methods.
+ raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node))
+
+ # Check for _call_user_data_handler() since this could conceivably
+ # used with other DOM implementations (one of the FourThought
+ # DOMs, perhaps?).
+ if hasattr(node, '_call_user_data_handler'):
+ node._call_user_data_handler(operation, node, clone)
+ return clone
+
+ xml.dom.minidom._clone_node = _clone_node
+
--- /dev/null
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+
+ident = "$Id$"
+
+import weakref
+from cStringIO import StringIO
+from Namespaces import OASIS, XMLNS, WSA, WSA_LIST, WSAW_LIST, WSRF_V1_2, WSRF
+from Utility import Collection, CollectionNS, DOM, ElementProxy, basejoin
+from XMLSchema import XMLSchema, SchemaReader, WSDLToolsAdapter
+
+
+class WSDLReader:
+ """A WSDLReader creates WSDL instances from urls and xml data."""
+
+ # Custom subclasses of WSDLReader may wish to implement a caching
+ # strategy or other optimizations. Because application needs vary
+ # so widely, we don't try to provide any caching by default.
+
+ def loadFromStream(self, stream, name=None):
+ """Return a WSDL instance loaded from a stream object."""
+ document = DOM.loadDocument(stream)
+ wsdl = WSDL()
+ if name:
+ wsdl.location = name
+ elif hasattr(stream, 'name'):
+ wsdl.location = stream.name
+ wsdl.load(document)
+ return wsdl
+
+ def loadFromURL(self, url):
+ """Return a WSDL instance loaded from the given url."""
+ document = DOM.loadFromURL(url)
+ wsdl = WSDL()
+ wsdl.location = url
+ wsdl.load(document)
+ return wsdl
+
+ def loadFromString(self, data):
+ """Return a WSDL instance loaded from an xml string."""
+ return self.loadFromStream(StringIO(data))
+
+ def loadFromFile(self, filename):
+ """Return a WSDL instance loaded from the given file."""
+ file = open(filename, 'rb')
+ try:
+ wsdl = self.loadFromStream(file)
+ finally:
+ file.close()
+ return wsdl
+
+class WSDL:
+ """A WSDL object models a WSDL service description. WSDL objects
+ may be created manually or loaded from an xml representation
+ using a WSDLReader instance."""
+
+ def __init__(self, targetNamespace=None, strict=1):
+ self.targetNamespace = targetNamespace or 'urn:this-document.wsdl'
+ self.documentation = ''
+ self.location = None
+ self.document = None
+ self.name = None
+ self.services = CollectionNS(self)
+ self.messages = CollectionNS(self)
+ self.portTypes = CollectionNS(self)
+ self.bindings = CollectionNS(self)
+ self.imports = Collection(self)
+ self.types = Types(self)
+ self.extensions = []
+ self.strict = strict
+
+ def __del__(self):
+ if self.document is not None:
+ self.document.unlink()
+
+ version = '1.1'
+
+ def addService(self, name, documentation='', targetNamespace=None):
+ if self.services.has_key(name):
+ raise WSDLError(
+ 'Duplicate service element: %s' % name
+ )
+ item = Service(name, documentation)
+ if targetNamespace:
+ item.targetNamespace = targetNamespace
+ self.services[name] = item
+ return item
+
+ def addMessage(self, name, documentation='', targetNamespace=None):
+ if self.messages.has_key(name):
+ raise WSDLError(
+ 'Duplicate message element: %s.' % name
+ )
+ item = Message(name, documentation)
+ if targetNamespace:
+ item.targetNamespace = targetNamespace
+ self.messages[name] = item
+ return item
+
+ def addPortType(self, name, documentation='', targetNamespace=None):
+ if self.portTypes.has_key(name):
+ raise WSDLError(
+ 'Duplicate portType element: name'
+ )
+ item = PortType(name, documentation)
+ if targetNamespace:
+ item.targetNamespace = targetNamespace
+ self.portTypes[name] = item
+ return item
+
+ def addBinding(self, name, type, documentation='', targetNamespace=None):
+ if self.bindings.has_key(name):
+ raise WSDLError(
+ 'Duplicate binding element: %s' % name
+ )
+ item = Binding(name, type, documentation)
+ if targetNamespace:
+ item.targetNamespace = targetNamespace
+ self.bindings[name] = item
+ return item
+
+ def addImport(self, namespace, location):
+ item = ImportElement(namespace, location)
+ self.imports[namespace] = item
+ return item
+
+ def toDom(self):
+ """ Generate a DOM representation of the WSDL instance.
+ Not dealing with generating XML Schema, thus the targetNamespace
+ of all XML Schema elements or types used by WSDL message parts
+ needs to be specified via import information items.
+ """
+ namespaceURI = DOM.GetWSDLUri(self.version)
+ self.document = DOM.createDocument(namespaceURI ,'wsdl:definitions')
+
+ # Set up a couple prefixes for easy reading.
+ child = DOM.getElement(self.document, None)
+ child.setAttributeNS(None, 'targetNamespace', self.targetNamespace)
+ child.setAttributeNS(XMLNS.BASE, 'xmlns:wsdl', namespaceURI)
+ child.setAttributeNS(XMLNS.BASE, 'xmlns:xsd', 'http://www.w3.org/1999/XMLSchema')
+ child.setAttributeNS(XMLNS.BASE, 'xmlns:soap', 'http://schemas.xmlsoap.org/wsdl/soap/')
+ child.setAttributeNS(XMLNS.BASE, 'xmlns:tns', self.targetNamespace)
+
+ if self.name:
+ child.setAttributeNS(None, 'name', self.name)
+
+ # wsdl:import
+ for item in self.imports:
+ item.toDom()
+ # wsdl:message
+ for item in self.messages:
+ item.toDom()
+ # wsdl:portType
+ for item in self.portTypes:
+ item.toDom()
+ # wsdl:binding
+ for item in self.bindings:
+ item.toDom()
+ # wsdl:service
+ for item in self.services:
+ item.toDom()
+
+ def load(self, document):
+ # We save a reference to the DOM document to ensure that elements
+ # saved as "extensions" will continue to have a meaningful context
+ # for things like namespace references. The lifetime of the DOM
+ # document is bound to the lifetime of the WSDL instance.
+ self.document = document
+
+ definitions = DOM.getElement(document, 'definitions', None, None)
+ if definitions is None:
+ raise WSDLError(
+ 'Missing <definitions> element.'
+ )
+ self.version = DOM.WSDLUriToVersion(definitions.namespaceURI)
+ NS_WSDL = DOM.GetWSDLUri(self.version)
+
+ self.targetNamespace = DOM.getAttr(definitions, 'targetNamespace',
+ None, None)
+ self.name = DOM.getAttr(definitions, 'name', None, None)
+ self.documentation = GetDocumentation(definitions)
+
+ #
+ # Retrieve all <wsdl:import>'s, append all children of imported
+ # document to main document. First iteration grab all original
+ # <wsdl:import>'s from document, second iteration grab all
+ # "imported" <wsdl:imports> from document, etc break out when
+ # no more <wsdl:import>'s.
+ #
+ imported = []
+ base_location = self.location
+ do_it = True
+ while do_it:
+ do_it = False
+ for element in DOM.getElements(definitions, 'import', NS_WSDL):
+ location = DOM.getAttr(element, 'location')
+
+ if base_location is not None:
+ location = basejoin(base_location, location)
+
+ if location not in imported:
+ do_it = True
+ self._import(document, element, base_location)
+ imported.append(location)
+ else:
+ definitions.removeChild(element)
+
+ base_location = None
+
+ #
+ # No more <wsdl:import>'s, now load up all other
+ # WSDL information items.
+ #
+ for element in DOM.getElements(definitions, None, None):
+ targetNamespace = DOM.getAttr(element, 'targetNamespace')
+ localName = element.localName
+
+ if not DOM.nsUriMatch(element.namespaceURI, NS_WSDL):
+ if localName == 'schema':
+ tns = DOM.getAttr(element, 'targetNamespace')
+ reader = SchemaReader(base_url=self.imports[tns].location)
+ schema = reader.loadFromNode(WSDLToolsAdapter(self),
+ element)
+# schema.setBaseUrl(self.location)
+ self.types.addSchema(schema)
+ else:
+ self.extensions.append(element)
+ continue
+
+ elif localName == 'message':
+ name = DOM.getAttr(element, 'name')
+ docs = GetDocumentation(element)
+ message = self.addMessage(name, docs, targetNamespace)
+ parts = DOM.getElements(element, 'part', NS_WSDL)
+ message.load(parts)
+ continue
+
+ elif localName == 'portType':
+ name = DOM.getAttr(element, 'name')
+ docs = GetDocumentation(element)
+ ptype = self.addPortType(name, docs, targetNamespace)
+ #operations = DOM.getElements(element, 'operation', NS_WSDL)
+ #ptype.load(operations)
+ ptype.load(element)
+ continue
+
+ elif localName == 'binding':
+ name = DOM.getAttr(element, 'name')
+ type = DOM.getAttr(element, 'type', default=None)
+ if type is None:
+ raise WSDLError(
+ 'Missing type attribute for binding %s.' % name
+ )
+ type = ParseQName(type, element)
+ docs = GetDocumentation(element)
+ binding = self.addBinding(name, type, docs, targetNamespace)
+ operations = DOM.getElements(element, 'operation', NS_WSDL)
+ binding.load(operations)
+ binding.load_ex(GetExtensions(element))
+ continue
+
+ elif localName == 'service':
+ name = DOM.getAttr(element, 'name')
+ docs = GetDocumentation(element)
+ service = self.addService(name, docs, targetNamespace)
+ ports = DOM.getElements(element, 'port', NS_WSDL)
+ service.load(ports)
+ service.load_ex(GetExtensions(element))
+ continue
+
+ elif localName == 'types':
+ self.types.documentation = GetDocumentation(element)
+ base_location = DOM.getAttr(element, 'base-location')
+ if base_location:
+ element.removeAttribute('base-location')
+ base_location = base_location or self.location
+ reader = SchemaReader(base_url=base_location)
+ for item in DOM.getElements(element, None, None):
+ if item.localName == 'schema':
+ schema = reader.loadFromNode(WSDLToolsAdapter(self), item)
+ # XXX <types> could have been imported
+ #schema.setBaseUrl(self.location)
+ schema.setBaseUrl(base_location)
+ self.types.addSchema(schema)
+ else:
+ self.types.addExtension(item)
+ # XXX remove the attribute
+ # element.removeAttribute('base-location')
+ continue
+
+ def _import(self, document, element, base_location=None):
+ '''Algo take <import> element's children, clone them,
+ and add them to the main document. Support for relative
+ locations is a bit complicated. The orig document context
+ is lost, so we need to store base location in DOM elements
+ representing <types>, by creating a special temporary
+ "base-location" attribute, and <import>, by resolving
+ the relative "location" and storing it as "location".
+
+ document -- document we are loading
+ element -- DOM Element representing <import>
+ base_location -- location of document from which this
+ <import> was gleaned.
+ '''
+ namespace = DOM.getAttr(element, 'namespace', default=None)
+ location = DOM.getAttr(element, 'location', default=None)
+ if namespace is None or location is None:
+ raise WSDLError(
+ 'Invalid import element (missing namespace or location).'
+ )
+ if base_location:
+ location = basejoin(base_location, location)
+ element.setAttributeNS(None, 'location', location)
+
+ obimport = self.addImport(namespace, location)
+ obimport._loaded = 1
+
+ importdoc = DOM.loadFromURL(location)
+ try:
+ if location.find('#') > -1:
+ idref = location.split('#')[-1]
+ imported = DOM.getElementById(importdoc, idref)
+ else:
+ imported = importdoc.documentElement
+ if imported is None:
+ raise WSDLError(
+ 'Import target element not found for: %s' % location
+ )
+
+ imported_tns = DOM.findTargetNS(imported)
+ if imported_tns != namespace:
+ return
+
+ if imported.localName == 'definitions':
+ imported_nodes = imported.childNodes
+ else:
+ imported_nodes = [imported]
+ parent = element.parentNode
+
+ parent.removeChild(element)
+
+ for node in imported_nodes:
+ if node.nodeType != node.ELEMENT_NODE:
+ continue
+ child = DOM.importNode(document, node, 1)
+ parent.appendChild(child)
+ child.setAttribute('targetNamespace', namespace)
+ attrsNS = imported._attrsNS
+ for attrkey in attrsNS.keys():
+ if attrkey[0] == DOM.NS_XMLNS:
+ attr = attrsNS[attrkey].cloneNode(1)
+ child.setAttributeNode(attr)
+
+ #XXX Quick Hack, should be in WSDL Namespace.
+ if child.localName == 'import':
+ rlocation = child.getAttributeNS(None, 'location')
+ alocation = basejoin(location, rlocation)
+ child.setAttribute('location', alocation)
+ elif child.localName == 'types':
+ child.setAttribute('base-location', location)
+
+ finally:
+ importdoc.unlink()
+ return location
+
+class Element:
+ """A class that provides common functions for WSDL element classes."""
+ def __init__(self, name=None, documentation=''):
+ self.name = name
+ self.documentation = documentation
+ self.extensions = []
+
+ def addExtension(self, item):
+ item.parent = weakref.ref(self)
+ self.extensions.append(item)
+
+ def getWSDL(self):
+ """Return the WSDL object that contains this information item."""
+ parent = self
+ while 1:
+ # skip any collections
+ if isinstance(parent, WSDL):
+ return parent
+ try: parent = parent.parent()
+ except: break
+
+ return None
+
+
+class ImportElement(Element):
+ def __init__(self, namespace, location):
+ self.namespace = namespace
+ self.location = location
+
+# def getWSDL(self):
+# """Return the WSDL object that contains this Message Part."""
+# return self.parent().parent()
+
+ def toDom(self):
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
+ epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'import')
+ epc.setAttributeNS(None, 'namespace', self.namespace)
+ epc.setAttributeNS(None, 'location', self.location)
+
+ _loaded = None
+
+
+class Types(Collection):
+ default = lambda self,k: k.targetNamespace
+ def __init__(self, parent):
+ Collection.__init__(self, parent)
+ self.documentation = ''
+ self.extensions = []
+
+ def addSchema(self, schema):
+ name = schema.targetNamespace
+ self[name] = schema
+ return schema
+
+ def addExtension(self, item):
+ self.extensions.append(item)
+
+
+class Message(Element):
+ def __init__(self, name, documentation=''):
+ Element.__init__(self, name, documentation)
+ self.parts = Collection(self)
+
+ def addPart(self, name, type=None, element=None):
+ if self.parts.has_key(name):
+ raise WSDLError(
+ 'Duplicate message part element: %s' % name
+ )
+ if type is None and element is None:
+ raise WSDLError(
+ 'Missing type or element attribute for part: %s' % name
+ )
+ item = MessagePart(name)
+ item.element = element
+ item.type = type
+ self.parts[name] = item
+ return item
+
+ def load(self, elements):
+ for element in elements:
+ name = DOM.getAttr(element, 'name')
+ part = MessagePart(name)
+ self.parts[name] = part
+ elemref = DOM.getAttr(element, 'element', default=None)
+ typeref = DOM.getAttr(element, 'type', default=None)
+ if typeref is None and elemref is None:
+ raise WSDLError(
+ 'No type or element attribute for part: %s' % name
+ )
+ if typeref is not None:
+ part.type = ParseTypeRef(typeref, element)
+ if elemref is not None:
+ part.element = ParseTypeRef(elemref, element)
+
+# def getElementDeclaration(self):
+# """Return the XMLSchema.ElementDeclaration instance or None"""
+# element = None
+# if self.element:
+# nsuri,name = self.element
+# wsdl = self.getWSDL()
+# if wsdl.types.has_key(nsuri) and wsdl.types[nsuri].elements.has_key(name):
+# element = wsdl.types[nsuri].elements[name]
+# return element
+#
+# def getTypeDefinition(self):
+# """Return the XMLSchema.TypeDefinition instance or None"""
+# type = None
+# if self.type:
+# nsuri,name = self.type
+# wsdl = self.getWSDL()
+# if wsdl.types.has_key(nsuri) and wsdl.types[nsuri].types.has_key(name):
+# type = wsdl.types[nsuri].types[name]
+# return type
+
+# def getWSDL(self):
+# """Return the WSDL object that contains this Message Part."""
+# return self.parent().parent()
+
+ def toDom(self):
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
+ epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'message')
+ epc.setAttributeNS(None, 'name', self.name)
+
+ for part in self.parts:
+ part.toDom(epc._getNode())
+
+
+class MessagePart(Element):
+ def __init__(self, name):
+ Element.__init__(self, name, '')
+ self.element = None
+ self.type = None
+
+# def getWSDL(self):
+# """Return the WSDL object that contains this Message Part."""
+# return self.parent().parent().parent().parent()
+
+ def getTypeDefinition(self):
+ wsdl = self.getWSDL()
+ nsuri,name = self.type
+ schema = wsdl.types.get(nsuri, {})
+ return schema.get(name)
+
+ def getElementDeclaration(self):
+ wsdl = self.getWSDL()
+ nsuri,name = self.element
+ schema = wsdl.types.get(nsuri, {})
+ return schema.get(name)
+
+ def toDom(self, node):
+ """node -- node representing message"""
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, node)
+ epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'part')
+ epc.setAttributeNS(None, 'name', self.name)
+
+ if self.element is not None:
+ ns,name = self.element
+ prefix = epc.getPrefix(ns)
+ epc.setAttributeNS(None, 'element', '%s:%s'%(prefix,name))
+ elif self.type is not None:
+ ns,name = self.type
+ prefix = epc.getPrefix(ns)
+ epc.setAttributeNS(None, 'type', '%s:%s'%(prefix,name))
+
+
+class PortType(Element):
+ '''PortType has a anyAttribute, thus must provide for an extensible
+ mechanism for supporting such attributes. ResourceProperties is
+ specified in WS-ResourceProperties. wsa:Action is specified in
+ WS-Address.
+
+ Instance Data:
+ name -- name attribute
+ resourceProperties -- optional. wsr:ResourceProperties attribute,
+ value is a QName this is Parsed into a (namespaceURI, name)
+ that represents a Global Element Declaration.
+ operations
+ '''
+
+ def __init__(self, name, documentation=''):
+ Element.__init__(self, name, documentation)
+ self.operations = Collection(self)
+ self.resourceProperties = None
+
+# def getWSDL(self):
+# return self.parent().parent()
+
+ def getTargetNamespace(self):
+ return self.targetNamespace or self.getWSDL().targetNamespace
+
+ def getResourceProperties(self):
+ return self.resourceProperties
+
+ def addOperation(self, name, documentation='', parameterOrder=None):
+ item = Operation(name, documentation, parameterOrder)
+ self.operations[name] = item
+ return item
+
+ def load(self, element):
+ self.name = DOM.getAttr(element, 'name')
+ self.documentation = GetDocumentation(element)
+ self.targetNamespace = DOM.getAttr(element, 'targetNamespace')
+
+ for nsuri in WSRF_V1_2.PROPERTIES.XSD_LIST:
+ if DOM.hasAttr(element, 'ResourceProperties', nsuri):
+ rpref = DOM.getAttr(element, 'ResourceProperties', nsuri)
+ self.resourceProperties = ParseQName(rpref, element)
+
+ NS_WSDL = DOM.GetWSDLUri(self.getWSDL().version)
+ elements = DOM.getElements(element, 'operation', NS_WSDL)
+ for element in elements:
+ name = DOM.getAttr(element, 'name')
+ docs = GetDocumentation(element)
+ param_order = DOM.getAttr(element, 'parameterOrder', default=None)
+ if param_order is not None:
+ param_order = param_order.split(' ')
+ operation = self.addOperation(name, docs, param_order)
+
+ item = DOM.getElement(element, 'input', None, None)
+ if item is not None:
+ name = DOM.getAttr(item, 'name')
+ docs = GetDocumentation(item)
+ msgref = DOM.getAttr(item, 'message')
+ message = ParseQName(msgref, item)
+ for WSA in WSA_LIST + WSAW_LIST:
+ action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None)
+ if action: break
+ operation.setInput(message, name, docs, action)
+
+ item = DOM.getElement(element, 'output', None, None)
+ if item is not None:
+ name = DOM.getAttr(item, 'name')
+ docs = GetDocumentation(item)
+ msgref = DOM.getAttr(item, 'message')
+ message = ParseQName(msgref, item)
+ for WSA in WSA_LIST + WSAW_LIST:
+ action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None)
+ if action: break
+ operation.setOutput(message, name, docs, action)
+
+ for item in DOM.getElements(element, 'fault', None):
+ name = DOM.getAttr(item, 'name')
+ docs = GetDocumentation(item)
+ msgref = DOM.getAttr(item, 'message')
+ message = ParseQName(msgref, item)
+ for WSA in WSA_LIST + WSAW_LIST:
+ action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None)
+ if action: break
+ operation.addFault(message, name, docs, action)
+
+ def toDom(self):
+ wsdl = self.getWSDL()
+
+ ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
+ epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'portType')
+ epc.setAttributeNS(None, 'name', self.name)
+ if self.resourceProperties:
+ ns,name = self.resourceProperties
+ prefix = epc.getPrefix(ns)
+ epc.setAttributeNS(WSRF.PROPERTIES.LATEST, 'ResourceProperties',
+ '%s:%s'%(prefix,name))
+
+ for op in self.operations:
+ op.toDom(epc._getNode())
+
+
+
+class Operation(Element):
+ def __init__(self, name, documentation='', parameterOrder=None):
+ Element.__init__(self, name, documentation)
+ self.parameterOrder = parameterOrder
+ self.faults = Collection(self)
+ self.input = None
+ self.output = None
+
+ def getWSDL(self):
+ """Return the WSDL object that contains this Operation."""
+ return self.parent().parent().parent().parent()
+
+ def getPortType(self):
+ return self.parent().parent()
+
+ def getInputAction(self):
+ """wsa:Action attribute"""
+ return GetWSAActionInput(self)
+
+ def getInputMessage(self):
+ if self.input is None:
+ return None
+ wsdl = self.getPortType().getWSDL()
+ return wsdl.messages[self.input.message]
+
+ def getOutputAction(self):
+ """wsa:Action attribute"""
+ return GetWSAActionOutput(self)
+
+ def getOutputMessage(self):
+ if self.output is None:
+ return None
+ wsdl = self.getPortType().getWSDL()
+ return wsdl.messages[self.output.message]
+
+ def getFaultAction(self, name):
+ """wsa:Action attribute"""
+ return GetWSAActionFault(self, name)
+
+ def getFaultMessage(self, name):
+ wsdl = self.getPortType().getWSDL()
+ return wsdl.messages[self.faults[name].message]
+
+ def addFault(self, message, name, documentation='', action=None):
+ if self.faults.has_key(name):
+ raise WSDLError(
+ 'Duplicate fault element: %s' % name
+ )
+ item = MessageRole('fault', message, name, documentation, action)
+ self.faults[name] = item
+ return item
+
+ def setInput(self, message, name='', documentation='', action=None):
+ self.input = MessageRole('input', message, name, documentation, action)
+ self.input.parent = weakref.ref(self)
+ return self.input
+
+ def setOutput(self, message, name='', documentation='', action=None):
+ self.output = MessageRole('output', message, name, documentation, action)
+ self.output.parent = weakref.ref(self)
+ return self.output
+
+ def toDom(self, node):
+ wsdl = self.getWSDL()
+
+ ep = ElementProxy(None, node)
+ epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'operation')
+ epc.setAttributeNS(None, 'name', self.name)
+ node = epc._getNode()
+ if self.input:
+ self.input.toDom(node)
+ if self.output:
+ self.output.toDom(node)
+ for fault in self.faults:
+ fault.toDom(node)
+
+
+class MessageRole(Element):
+ def __init__(self, type, message, name='', documentation='', action=None):
+ Element.__init__(self, name, documentation)
+ self.message = message
+ self.type = type
+ self.action = action
+
+ def getWSDL(self):
+ """Return the WSDL object that contains this information item."""
+ parent = self
+ while 1:
+ # skip any collections
+ if isinstance(parent, WSDL):
+ return parent
+ try: parent = parent.parent()
+ except: break
+
+ return None
+
+ def getMessage(self):
+ """Return the WSDL object that represents the attribute message
+ (namespaceURI, name) tuple
+ """
+ wsdl = self.getWSDL()
+ return wsdl.messages[self.message]
+
+ def toDom(self, node):
+ wsdl = self.getWSDL()
+
+ ep = ElementProxy(None, node)
+ epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), self.type)
+ if not isinstance(self.message, basestring) and len(self.message) == 2:
+ ns,name = self.message
+ prefix = epc.getPrefix(ns)
+ epc.setAttributeNS(None, 'message', '%s:%s' %(prefix,name))
+ else:
+ epc.setAttributeNS(None, 'message', self.message)
+
+ if self.action:
+ epc.setAttributeNS(WSA.ADDRESS, 'Action', self.action)
+
+ if self.name:
+ epc.setAttributeNS(None, 'name', self.name)
+
+
+class Binding(Element):
+ def __init__(self, name, type, documentation=''):
+ Element.__init__(self, name, documentation)
+ self.operations = Collection(self)
+ self.type = type
+
+# def getWSDL(self):
+# """Return the WSDL object that contains this binding."""
+# return self.parent().parent()
+
+ def getPortType(self):
+ """Return the PortType object associated with this binding."""
+ return self.getWSDL().portTypes[self.type]
+
+ def findBinding(self, kind):
+ for item in self.extensions:
+ if isinstance(item, kind):
+ return item
+ return None
+
+ def findBindings(self, kind):
+ return [ item for item in self.extensions if isinstance(item, kind) ]
+
+ def addOperationBinding(self, name, documentation=''):
+ item = OperationBinding(name, documentation)
+ self.operations[name] = item
+ return item
+
+ def load(self, elements):
+ for element in elements:
+ name = DOM.getAttr(element, 'name')
+ docs = GetDocumentation(element)
+ opbinding = self.addOperationBinding(name, docs)
+ opbinding.load_ex(GetExtensions(element))
+
+ item = DOM.getElement(element, 'input', None, None)
+ if item is not None:
+ #TODO: addInputBinding?
+ mbinding = MessageRoleBinding('input')
+ mbinding.documentation = GetDocumentation(item)
+ opbinding.input = mbinding
+ mbinding.load_ex(GetExtensions(item))
+ mbinding.parent = weakref.ref(opbinding)
+
+ item = DOM.getElement(element, 'output', None, None)
+ if item is not None:
+ mbinding = MessageRoleBinding('output')
+ mbinding.documentation = GetDocumentation(item)
+ opbinding.output = mbinding
+ mbinding.load_ex(GetExtensions(item))
+ mbinding.parent = weakref.ref(opbinding)
+
+ for item in DOM.getElements(element, 'fault', None):
+ name = DOM.getAttr(item, 'name')
+ mbinding = MessageRoleBinding('fault', name)
+ mbinding.documentation = GetDocumentation(item)
+ opbinding.faults[name] = mbinding
+ mbinding.load_ex(GetExtensions(item))
+ mbinding.parent = weakref.ref(opbinding)
+
+ def load_ex(self, elements):
+ for e in elements:
+ ns, name = e.namespaceURI, e.localName
+ if ns in DOM.NS_SOAP_BINDING_ALL and name == 'binding':
+ transport = DOM.getAttr(e, 'transport', default=None)
+ style = DOM.getAttr(e, 'style', default='document')
+ ob = SoapBinding(transport, style)
+ self.addExtension(ob)
+ continue
+ elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'binding':
+ verb = DOM.getAttr(e, 'verb')
+ ob = HttpBinding(verb)
+ self.addExtension(ob)
+ continue
+ else:
+ self.addExtension(e)
+
+ def toDom(self):
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
+ epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'binding')
+ epc.setAttributeNS(None, 'name', self.name)
+
+ ns,name = self.type
+ prefix = epc.getPrefix(ns)
+ epc.setAttributeNS(None, 'type', '%s:%s' %(prefix,name))
+
+ node = epc._getNode()
+ for ext in self.extensions:
+ ext.toDom(node)
+ for op_binding in self.operations:
+ op_binding.toDom(node)
+
+
+class OperationBinding(Element):
+ def __init__(self, name, documentation=''):
+ Element.__init__(self, name, documentation)
+ self.input = None
+ self.output = None
+ self.faults = Collection(self)
+
+# def getWSDL(self):
+# """Return the WSDL object that contains this binding."""
+# return self.parent().parent().parent().parent()
+
+
+ def getBinding(self):
+ """Return the parent Binding object of the operation binding."""
+ return self.parent().parent()
+
+ def getOperation(self):
+ """Return the abstract Operation associated with this binding."""
+ return self.getBinding().getPortType().operations[self.name]
+
+ def findBinding(self, kind):
+ for item in self.extensions:
+ if isinstance(item, kind):
+ return item
+ return None
+
+ def findBindings(self, kind):
+ return [ item for item in self.extensions if isinstance(item, kind) ]
+
+ def addInputBinding(self, binding):
+ if self.input is None:
+ self.input = MessageRoleBinding('input')
+ self.input.parent = weakref.ref(self)
+ self.input.addExtension(binding)
+ return binding
+
+ def addOutputBinding(self, binding):
+ if self.output is None:
+ self.output = MessageRoleBinding('output')
+ self.output.parent = weakref.ref(self)
+ self.output.addExtension(binding)
+ return binding
+
+ def addFaultBinding(self, name, binding):
+ fault = self.get(name, None)
+ if fault is None:
+ fault = MessageRoleBinding('fault', name)
+ fault.addExtension(binding)
+ return binding
+
+ def load_ex(self, elements):
+ for e in elements:
+ ns, name = e.namespaceURI, e.localName
+ if ns in DOM.NS_SOAP_BINDING_ALL and name == 'operation':
+ soapaction = DOM.getAttr(e, 'soapAction', default=None)
+ style = DOM.getAttr(e, 'style', default=None)
+ ob = SoapOperationBinding(soapaction, style)
+ self.addExtension(ob)
+ continue
+ elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'operation':
+ location = DOM.getAttr(e, 'location')
+ ob = HttpOperationBinding(location)
+ self.addExtension(ob)
+ continue
+ else:
+ self.addExtension(e)
+
+ def toDom(self, node):
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, node)
+ epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), 'operation')
+ epc.setAttributeNS(None, 'name', self.name)
+
+ node = epc._getNode()
+ for ext in self.extensions:
+ ext.toDom(node)
+ if self.input:
+ self.input.toDom(node)
+ if self.output:
+ self.output.toDom(node)
+ for fault in self.faults:
+ fault.toDom(node)
+
+
+class MessageRoleBinding(Element):
+ def __init__(self, type, name='', documentation=''):
+ Element.__init__(self, name, documentation)
+ self.type = type
+
+ def findBinding(self, kind):
+ for item in self.extensions:
+ if isinstance(item, kind):
+ return item
+ return None
+
+ def findBindings(self, kind):
+ return [ item for item in self.extensions if isinstance(item, kind) ]
+
+ def load_ex(self, elements):
+ for e in elements:
+ ns, name = e.namespaceURI, e.localName
+ if ns in DOM.NS_SOAP_BINDING_ALL and name == 'body':
+ encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
+ namespace = DOM.getAttr(e, 'namespace', default=None)
+ parts = DOM.getAttr(e, 'parts', default=None)
+ use = DOM.getAttr(e, 'use', default=None)
+ if use is None:
+ raise WSDLError(
+ 'Invalid soap:body binding element.'
+ )
+ ob = SoapBodyBinding(use, namespace, encstyle, parts)
+ self.addExtension(ob)
+ continue
+
+ elif ns in DOM.NS_SOAP_BINDING_ALL and name == 'fault':
+ encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
+ namespace = DOM.getAttr(e, 'namespace', default=None)
+ name = DOM.getAttr(e, 'name', default=None)
+ use = DOM.getAttr(e, 'use', default=None)
+ if use is None or name is None:
+ raise WSDLError(
+ 'Invalid soap:fault binding element.'
+ )
+ ob = SoapFaultBinding(name, use, namespace, encstyle)
+ self.addExtension(ob)
+ continue
+
+ elif ns in DOM.NS_SOAP_BINDING_ALL and name in (
+ 'header', 'headerfault'
+ ):
+ encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
+ namespace = DOM.getAttr(e, 'namespace', default=None)
+ message = DOM.getAttr(e, 'message')
+ part = DOM.getAttr(e, 'part')
+ use = DOM.getAttr(e, 'use')
+ if name == 'header':
+ _class = SoapHeaderBinding
+ else:
+ _class = SoapHeaderFaultBinding
+ message = ParseQName(message, e)
+ ob = _class(message, part, use, namespace, encstyle)
+ self.addExtension(ob)
+ continue
+
+ elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'urlReplacement':
+ ob = HttpUrlReplacementBinding()
+ self.addExtension(ob)
+ continue
+
+ elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'urlEncoded':
+ ob = HttpUrlEncodedBinding()
+ self.addExtension(ob)
+ continue
+
+ elif ns in DOM.NS_MIME_BINDING_ALL and name == 'multipartRelated':
+ ob = MimeMultipartRelatedBinding()
+ self.addExtension(ob)
+ ob.load_ex(GetExtensions(e))
+ continue
+
+ elif ns in DOM.NS_MIME_BINDING_ALL and name == 'content':
+ part = DOM.getAttr(e, 'part', default=None)
+ type = DOM.getAttr(e, 'type', default=None)
+ ob = MimeContentBinding(part, type)
+ self.addExtension(ob)
+ continue
+
+ elif ns in DOM.NS_MIME_BINDING_ALL and name == 'mimeXml':
+ part = DOM.getAttr(e, 'part', default=None)
+ ob = MimeXmlBinding(part)
+ self.addExtension(ob)
+ continue
+
+ else:
+ self.addExtension(e)
+
+ def toDom(self, node):
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, node)
+ epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), self.type)
+
+ node = epc._getNode()
+ for item in self.extensions:
+ if item: item.toDom(node)
+
+
+class Service(Element):
+ def __init__(self, name, documentation=''):
+ Element.__init__(self, name, documentation)
+ self.ports = Collection(self)
+
+ def getWSDL(self):
+ return self.parent().parent()
+
+ def addPort(self, name, binding, documentation=''):
+ item = Port(name, binding, documentation)
+ self.ports[name] = item
+ return item
+
+ def load(self, elements):
+ for element in elements:
+ name = DOM.getAttr(element, 'name', default=None)
+ docs = GetDocumentation(element)
+ binding = DOM.getAttr(element, 'binding', default=None)
+ if name is None or binding is None:
+ raise WSDLError(
+ 'Invalid port element.'
+ )
+ binding = ParseQName(binding, element)
+ port = self.addPort(name, binding, docs)
+ port.load_ex(GetExtensions(element))
+
+ def load_ex(self, elements):
+ for e in elements:
+ self.addExtension(e)
+
+ def toDom(self):
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, DOM.getElement(wsdl.document, None))
+ epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), "service")
+ epc.setAttributeNS(None, "name", self.name)
+
+ node = epc._getNode()
+ for port in self.ports:
+ port.toDom(node)
+
+
+class Port(Element):
+ def __init__(self, name, binding, documentation=''):
+ Element.__init__(self, name, documentation)
+ self.binding = binding
+
+# def getWSDL(self):
+# return self.parent().parent().getWSDL()
+
+ def getService(self):
+ """Return the Service object associated with this port."""
+ return self.parent().parent()
+
+ def getBinding(self):
+ """Return the Binding object that is referenced by this port."""
+ wsdl = self.getService().getWSDL()
+ return wsdl.bindings[self.binding]
+
+ def getPortType(self):
+ """Return the PortType object that is referenced by this port."""
+ wsdl = self.getService().getWSDL()
+ binding = wsdl.bindings[self.binding]
+ return wsdl.portTypes[binding.type]
+
+ def getAddressBinding(self):
+ """A convenience method to obtain the extension element used
+ as the address binding for the port."""
+ for item in self.extensions:
+ if isinstance(item, SoapAddressBinding) or \
+ isinstance(item, HttpAddressBinding):
+ return item
+ raise WSDLError(
+ 'No address binding found in port.'
+ )
+
+ def load_ex(self, elements):
+ for e in elements:
+ ns, name = e.namespaceURI, e.localName
+ if ns in DOM.NS_SOAP_BINDING_ALL and name == 'address':
+ location = DOM.getAttr(e, 'location', default=None)
+ ob = SoapAddressBinding(location)
+ self.addExtension(ob)
+ continue
+ elif ns in DOM.NS_HTTP_BINDING_ALL and name == 'address':
+ location = DOM.getAttr(e, 'location', default=None)
+ ob = HttpAddressBinding(location)
+ self.addExtension(ob)
+ continue
+ else:
+ self.addExtension(e)
+
+ def toDom(self, node):
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, node)
+ epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), "port")
+ epc.setAttributeNS(None, "name", self.name)
+
+ ns,name = self.binding
+ prefix = epc.getPrefix(ns)
+ epc.setAttributeNS(None, "binding", "%s:%s" %(prefix,name))
+
+ node = epc._getNode()
+ for ext in self.extensions:
+ ext.toDom(node)
+
+
+class SoapBinding:
+ def __init__(self, transport, style='rpc'):
+ self.transport = transport
+ self.style = style
+
+ def getWSDL(self):
+ return self.parent().getWSDL()
+
+ def toDom(self, node):
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, node)
+ epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'binding')
+ if self.transport:
+ epc.setAttributeNS(None, "transport", self.transport)
+ if self.style:
+ epc.setAttributeNS(None, "style", self.style)
+
+class SoapAddressBinding:
+ def __init__(self, location):
+ self.location = location
+
+ def getWSDL(self):
+ return self.parent().getWSDL()
+
+ def toDom(self, node):
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, node)
+ epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'address')
+ epc.setAttributeNS(None, "location", self.location)
+
+
+class SoapOperationBinding:
+ def __init__(self, soapAction=None, style=None):
+ self.soapAction = soapAction
+ self.style = style
+
+ def getWSDL(self):
+ return self.parent().getWSDL()
+
+ def toDom(self, node):
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, node)
+ epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'operation')
+ if self.soapAction:
+ epc.setAttributeNS(None, 'soapAction', self.soapAction)
+ if self.style:
+ epc.setAttributeNS(None, 'style', self.style)
+
+
+class SoapBodyBinding:
+ def __init__(self, use, namespace=None, encodingStyle=None, parts=None):
+ if not use in ('literal', 'encoded'):
+ raise WSDLError(
+ 'Invalid use attribute value: %s' % use
+ )
+ self.encodingStyle = encodingStyle
+ self.namespace = namespace
+ if type(parts) in (type(''), type(u'')):
+ parts = parts.split()
+ self.parts = parts
+ self.use = use
+
+ def getWSDL(self):
+ return self.parent().getWSDL()
+
+ def toDom(self, node):
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, node)
+ epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'body')
+ epc.setAttributeNS(None, "use", self.use)
+ epc.setAttributeNS(None, "namespace", self.namespace)
+
+
+class SoapFaultBinding:
+ def __init__(self, name, use, namespace=None, encodingStyle=None):
+ if not use in ('literal', 'encoded'):
+ raise WSDLError(
+ 'Invalid use attribute value: %s' % use
+ )
+ self.encodingStyle = encodingStyle
+ self.namespace = namespace
+ self.name = name
+ self.use = use
+
+ def getWSDL(self):
+ return self.parent().getWSDL()
+
+ def toDom(self, node):
+ wsdl = self.getWSDL()
+ ep = ElementProxy(None, node)
+ epc = ep.createAppendElement(DOM.GetWSDLSoapBindingUri(wsdl.version), 'body')
+ epc.setAttributeNS(None, "use", self.use)
+ epc.setAttributeNS(None, "name", self.name)
+ if self.namespace is not None:
+ epc.setAttributeNS(None, "namespace", self.namespace)
+ if self.encodingStyle is not None:
+ epc.setAttributeNS(None, "encodingStyle", self.encodingStyle)
+
+
+class SoapHeaderBinding:
+ def __init__(self, message, part, use, namespace=None, encodingStyle=None):
+ if not use in ('literal', 'encoded'):
+ raise WSDLError(
+ 'Invalid use attribute value: %s' % use
+ )
+ self.encodingStyle = encodingStyle
+ self.namespace = namespace
+ self.message = message
+ self.part = part
+ self.use = use
+
+ tagname = 'header'
+
+class SoapHeaderFaultBinding(SoapHeaderBinding):
+ tagname = 'headerfault'
+
+
+class HttpBinding:
+ def __init__(self, verb):
+ self.verb = verb
+
+class HttpAddressBinding:
+ def __init__(self, location):
+ self.location = location
+
+
+class HttpOperationBinding:
+ def __init__(self, location):
+ self.location = location
+
+class HttpUrlReplacementBinding:
+ pass
+
+
+class HttpUrlEncodedBinding:
+ pass
+
+
+class MimeContentBinding:
+ def __init__(self, part=None, type=None):
+ self.part = part
+ self.type = type
+
+
+class MimeXmlBinding:
+ def __init__(self, part=None):
+ self.part = part
+
+
+class MimeMultipartRelatedBinding:
+ def __init__(self):
+ self.parts = []
+
+ def load_ex(self, elements):
+ for e in elements:
+ ns, name = e.namespaceURI, e.localName
+ if ns in DOM.NS_MIME_BINDING_ALL and name == 'part':
+ self.parts.append(MimePartBinding())
+ continue
+
+
+class MimePartBinding:
+ def __init__(self):
+ self.items = []
+
+ def load_ex(self, elements):
+ for e in elements:
+ ns, name = e.namespaceURI, e.localName
+ if ns in DOM.NS_MIME_BINDING_ALL and name == 'content':
+ part = DOM.getAttr(e, 'part', default=None)
+ type = DOM.getAttr(e, 'type', default=None)
+ ob = MimeContentBinding(part, type)
+ self.items.append(ob)
+ continue
+
+ elif ns in DOM.NS_MIME_BINDING_ALL and name == 'mimeXml':
+ part = DOM.getAttr(e, 'part', default=None)
+ ob = MimeXmlBinding(part)
+ self.items.append(ob)
+ continue
+
+ elif ns in DOM.NS_SOAP_BINDING_ALL and name == 'body':
+ encstyle = DOM.getAttr(e, 'encodingStyle', default=None)
+ namespace = DOM.getAttr(e, 'namespace', default=None)
+ parts = DOM.getAttr(e, 'parts', default=None)
+ use = DOM.getAttr(e, 'use', default=None)
+ if use is None:
+ raise WSDLError(
+ 'Invalid soap:body binding element.'
+ )
+ ob = SoapBodyBinding(use, namespace, encstyle, parts)
+ self.items.append(ob)
+ continue
+
+
+class WSDLError(Exception):
+ pass
+
+
+
+def DeclareNSPrefix(writer, prefix, nsuri):
+ if writer.hasNSPrefix(nsuri):
+ return
+ writer.declareNSPrefix(prefix, nsuri)
+
+def ParseTypeRef(value, element):
+ parts = value.split(':', 1)
+ if len(parts) == 1:
+ return (DOM.findTargetNS(element), value)
+ nsuri = DOM.findNamespaceURI(parts[0], element)
+ return (nsuri, parts[1])
+
+def ParseQName(value, element):
+ nameref = value.split(':', 1)
+ if len(nameref) == 2:
+ nsuri = DOM.findNamespaceURI(nameref[0], element)
+ name = nameref[-1]
+ else:
+ nsuri = DOM.findTargetNS(element)
+ name = nameref[-1]
+ return nsuri, name
+
+def GetDocumentation(element):
+ docnode = DOM.getElement(element, 'documentation', None, None)
+ if docnode is not None:
+ return DOM.getElementText(docnode)
+ return ''
+
+def GetExtensions(element):
+ return [ item for item in DOM.getElements(element, None, None)
+ if item.namespaceURI != DOM.NS_WSDL ]
+
+def GetWSAActionFault(operation, name):
+ """Find wsa:Action attribute, and return value or WSA.FAULT
+ for the default.
+ """
+ attr = operation.faults[name].action
+ if attr is not None:
+ return attr
+ return WSA.FAULT
+
+def GetWSAActionInput(operation):
+ """Find wsa:Action attribute, and return value or the default."""
+ attr = operation.input.action
+ if attr is not None:
+ return attr
+ portType = operation.getPortType()
+ targetNamespace = portType.getTargetNamespace()
+ ptName = portType.name
+ msgName = operation.input.name
+ if not msgName:
+ msgName = operation.name + 'Request'
+ if targetNamespace.endswith('/'):
+ return '%s%s/%s' %(targetNamespace, ptName, msgName)
+ return '%s/%s/%s' %(targetNamespace, ptName, msgName)
+
+def GetWSAActionOutput(operation):
+ """Find wsa:Action attribute, and return value or the default."""
+ attr = operation.output.action
+ if attr is not None:
+ return attr
+ targetNamespace = operation.getPortType().getTargetNamespace()
+ ptName = operation.getPortType().name
+ msgName = operation.output.name
+ if not msgName:
+ msgName = operation.name + 'Response'
+ if targetNamespace.endswith('/'):
+ return '%s%s/%s' %(targetNamespace, ptName, msgName)
+ return '%s/%s/%s' %(targetNamespace, ptName, msgName)
+
+def FindExtensions(object, kind, t_type=type(())):
+ if isinstance(kind, t_type):
+ result = []
+ namespaceURI, name = kind
+ return [ item for item in object.extensions
+ if hasattr(item, 'nodeType') \
+ and DOM.nsUriMatch(namespaceURI, item.namespaceURI) \
+ and item.name == name ]
+ return [ item for item in object.extensions if isinstance(item, kind) ]
+
+def FindExtension(object, kind, t_type=type(())):
+ if isinstance(kind, t_type):
+ namespaceURI, name = kind
+ for item in object.extensions:
+ if hasattr(item, 'nodeType') \
+ and DOM.nsUriMatch(namespaceURI, item.namespaceURI) \
+ and item.name == name:
+ return item
+ else:
+ for item in object.extensions:
+ if isinstance(item, kind):
+ return item
+ return None
+
+
+class SOAPCallInfo:
+ """SOAPCallInfo captures the important binding information about a
+ SOAP operation, in a structure that is easier to work with than
+ raw WSDL structures."""
+
+ def __init__(self, methodName):
+ self.methodName = methodName
+ self.inheaders = []
+ self.outheaders = []
+ self.inparams = []
+ self.outparams = []
+ self.retval = None
+
+ encodingStyle = DOM.NS_SOAP_ENC
+ documentation = ''
+ soapAction = None
+ transport = None
+ namespace = None
+ location = None
+ use = 'encoded'
+ style = 'rpc'
+
+ def addInParameter(self, name, type, namespace=None, element_type=0):
+ """Add an input parameter description to the call info."""
+ parameter = ParameterInfo(name, type, namespace, element_type)
+ self.inparams.append(parameter)
+ return parameter
+
+ def addOutParameter(self, name, type, namespace=None, element_type=0):
+ """Add an output parameter description to the call info."""
+ parameter = ParameterInfo(name, type, namespace, element_type)
+ self.outparams.append(parameter)
+ return parameter
+
+ def setReturnParameter(self, name, type, namespace=None, element_type=0):
+ """Set the return parameter description for the call info."""
+ parameter = ParameterInfo(name, type, namespace, element_type)
+ self.retval = parameter
+ return parameter
+
+ def addInHeaderInfo(self, name, type, namespace, element_type=0,
+ mustUnderstand=0):
+ """Add an input SOAP header description to the call info."""
+ headerinfo = HeaderInfo(name, type, namespace, element_type)
+ if mustUnderstand:
+ headerinfo.mustUnderstand = 1
+ self.inheaders.append(headerinfo)
+ return headerinfo
+
+ def addOutHeaderInfo(self, name, type, namespace, element_type=0,
+ mustUnderstand=0):
+ """Add an output SOAP header description to the call info."""
+ headerinfo = HeaderInfo(name, type, namespace, element_type)
+ if mustUnderstand:
+ headerinfo.mustUnderstand = 1
+ self.outheaders.append(headerinfo)
+ return headerinfo
+
+ def getInParameters(self):
+ """Return a sequence of the in parameters of the method."""
+ return self.inparams
+
+ def getOutParameters(self):
+ """Return a sequence of the out parameters of the method."""
+ return self.outparams
+
+ def getReturnParameter(self):
+ """Return param info about the return value of the method."""
+ return self.retval
+
+ def getInHeaders(self):
+ """Return a sequence of the in headers of the method."""
+ return self.inheaders
+
+ def getOutHeaders(self):
+ """Return a sequence of the out headers of the method."""
+ return self.outheaders
+
+
+class ParameterInfo:
+ """A ParameterInfo object captures parameter binding information."""
+ def __init__(self, name, type, namespace=None, element_type=0):
+ if element_type:
+ self.element_type = 1
+ if namespace is not None:
+ self.namespace = namespace
+ self.name = name
+ self.type = type
+
+ element_type = 0
+ namespace = None
+ default = None
+
+
+class HeaderInfo(ParameterInfo):
+ """A HeaderInfo object captures SOAP header binding information."""
+ def __init__(self, name, type, namespace, element_type=None):
+ ParameterInfo.__init__(self, name, type, namespace, element_type)
+
+ mustUnderstand = 0
+ actor = None
+
+
+def callInfoFromWSDL(port, name):
+ """Return a SOAPCallInfo given a WSDL port and operation name."""
+ wsdl = port.getService().getWSDL()
+ binding = port.getBinding()
+ portType = binding.getPortType()
+ operation = portType.operations[name]
+ opbinding = binding.operations[name]
+ messages = wsdl.messages
+ callinfo = SOAPCallInfo(name)
+
+ addrbinding = port.getAddressBinding()
+ if not isinstance(addrbinding, SoapAddressBinding):
+ raise ValueError, 'Unsupported binding type.'
+ callinfo.location = addrbinding.location
+
+ soapbinding = binding.findBinding(SoapBinding)
+ if soapbinding is None:
+ raise ValueError, 'Missing soap:binding element.'
+ callinfo.transport = soapbinding.transport
+ callinfo.style = soapbinding.style or 'document'
+
+ soap_op_binding = opbinding.findBinding(SoapOperationBinding)
+ if soap_op_binding is not None:
+ callinfo.soapAction = soap_op_binding.soapAction
+ callinfo.style = soap_op_binding.style or callinfo.style
+
+ parameterOrder = operation.parameterOrder
+
+ if operation.input is not None:
+ message = messages[operation.input.message]
+ msgrole = opbinding.input
+
+ mime = msgrole.findBinding(MimeMultipartRelatedBinding)
+ if mime is not None:
+ raise ValueError, 'Mime bindings are not supported.'
+ else:
+ for item in msgrole.findBindings(SoapHeaderBinding):
+ part = messages[item.message].parts[item.part]
+ header = callinfo.addInHeaderInfo(
+ part.name,
+ part.element or part.type,
+ item.namespace,
+ element_type = part.element and 1 or 0
+ )
+ header.encodingStyle = item.encodingStyle
+
+ body = msgrole.findBinding(SoapBodyBinding)
+ if body is None:
+ raise ValueError, 'Missing soap:body binding.'
+ callinfo.encodingStyle = body.encodingStyle
+ callinfo.namespace = body.namespace
+ callinfo.use = body.use
+
+ if body.parts is not None:
+ parts = []
+ for name in body.parts:
+ parts.append(message.parts[name])
+ else:
+ parts = message.parts.values()
+
+ for part in parts:
+ callinfo.addInParameter(
+ part.name,
+ part.element or part.type,
+ element_type = part.element and 1 or 0
+ )
+
+ if operation.output is not None:
+ try:
+ message = messages[operation.output.message]
+ except KeyError:
+ if self.strict:
+ raise RuntimeError(
+ "Recieved message not defined in the WSDL schema: %s" %
+ operation.output.message)
+ else:
+ message = wsdl.addMessage(operation.output.message)
+ print "Warning:", \
+ "Recieved message not defined in the WSDL schema.", \
+ "Adding it."
+ print "Message:", operation.output.message
+
+ msgrole = opbinding.output
+
+ mime = msgrole.findBinding(MimeMultipartRelatedBinding)
+ if mime is not None:
+ raise ValueError, 'Mime bindings are not supported.'
+ else:
+ for item in msgrole.findBindings(SoapHeaderBinding):
+ part = messages[item.message].parts[item.part]
+ header = callinfo.addOutHeaderInfo(
+ part.name,
+ part.element or part.type,
+ item.namespace,
+ element_type = part.element and 1 or 0
+ )
+ header.encodingStyle = item.encodingStyle
+
+ body = msgrole.findBinding(SoapBodyBinding)
+ if body is None:
+ raise ValueError, 'Missing soap:body binding.'
+ callinfo.encodingStyle = body.encodingStyle
+ callinfo.namespace = body.namespace
+ callinfo.use = body.use
+
+ if body.parts is not None:
+ parts = []
+ for name in body.parts:
+ parts.append(message.parts[name])
+ else:
+ parts = message.parts.values()
+
+ if parts:
+ for part in parts:
+ callinfo.addOutParameter(
+ part.name,
+ part.element or part.type,
+ element_type = part.element and 1 or 0
+ )
+
+ return callinfo
--- /dev/null
+# Copyright (c) 2003, The Regents of the University of California,
+# through Lawrence Berkeley National Laboratory (subject to receipt of
+# any required approvals from the U.S. Dept. of Energy). All rights
+# reserved.
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+
+ident = "$Id$"
+
+import types, weakref, sys, warnings
+from Namespaces import SCHEMA, XMLNS, SOAP, APACHE
+from Utility import DOM, DOMException, Collection, SplitQName, basejoin
+from StringIO import StringIO
+
+# If we have no threading, this should be a no-op
+try:
+ from threading import RLock
+except ImportError:
+ class RLock:
+ def acquire():
+ pass
+ def release():
+ pass
+
+#
+# Collections in XMLSchema class
+#
+TYPES = 'types'
+ATTRIBUTE_GROUPS = 'attr_groups'
+ATTRIBUTES = 'attr_decl'
+ELEMENTS = 'elements'
+MODEL_GROUPS = 'model_groups'
+BUILT_IN_NAMESPACES = [SOAP.ENC,] + SCHEMA.XSD_LIST + [APACHE.AXIS_NS]
+
+def GetSchema(component):
+ """convience function for finding the parent XMLSchema instance.
+ """
+ parent = component
+ while not isinstance(parent, XMLSchema):
+ parent = parent._parent()
+ return parent
+
+class SchemaReader:
+ """A SchemaReader creates XMLSchema objects from urls and xml data.
+ """
+
+ namespaceToSchema = {}
+
+ def __init__(self, domReader=None, base_url=None):
+ """domReader -- class must implement DOMAdapterInterface
+ base_url -- base url string
+ """
+ self.__base_url = base_url
+ self.__readerClass = domReader
+ if not self.__readerClass:
+ self.__readerClass = DOMAdapter
+ self._includes = {}
+ self._imports = {}
+
+ def __setImports(self, schema):
+ """Add dictionary of imports to schema instance.
+ schema -- XMLSchema instance
+ """
+ for ns,val in schema.imports.items():
+ if self._imports.has_key(ns):
+ schema.addImportSchema(self._imports[ns])
+
+ def __setIncludes(self, schema):
+ """Add dictionary of includes to schema instance.
+ schema -- XMLSchema instance
+ """
+ for schemaLocation, val in schema.includes.items():
+ if self._includes.has_key(schemaLocation):
+ schema.addIncludeSchema(schemaLocation, self._imports[schemaLocation])
+
+ def addSchemaByLocation(self, location, schema):
+ """provide reader with schema document for a location.
+ """
+ self._includes[location] = schema
+
+ def addSchemaByNamespace(self, schema):
+ """provide reader with schema document for a targetNamespace.
+ """
+ self._imports[schema.targetNamespace] = schema
+
+ def loadFromNode(self, parent, element):
+ """element -- DOM node or document
+ parent -- WSDLAdapter instance
+ """
+ reader = self.__readerClass(element)
+ schema = XMLSchema(parent)
+ #HACK to keep a reference
+ schema.wsdl = parent
+ schema.setBaseUrl(self.__base_url)
+ schema.load(reader)
+ return schema
+
+ def loadFromStream(self, file, url=None):
+ """Return an XMLSchema instance loaded from a file object.
+ file -- file object
+ url -- base location for resolving imports/includes.
+ """
+ reader = self.__readerClass()
+ reader.loadDocument(file)
+ schema = XMLSchema()
+ if url is not None:
+ schema.setBaseUrl(url)
+ schema.load(reader)
+ self.__setIncludes(schema)
+ self.__setImports(schema)
+ return schema
+
+ def loadFromString(self, data):
+ """Return an XMLSchema instance loaded from an XML string.
+ data -- XML string
+ """
+ return self.loadFromStream(StringIO(data))
+
+ def loadFromURL(self, url, schema=None):
+ """Return an XMLSchema instance loaded from the given url.
+ url -- URL to dereference
+ schema -- Optional XMLSchema instance.
+ """
+ reader = self.__readerClass()
+ if self.__base_url:
+ url = basejoin(self.__base_url,url)
+
+ reader.loadFromURL(url)
+ schema = schema or XMLSchema()
+ schema.setBaseUrl(url)
+ schema.load(reader)
+ self.__setIncludes(schema)
+ self.__setImports(schema)
+ return schema
+
+ def loadFromFile(self, filename):
+ """Return an XMLSchema instance loaded from the given file.
+ filename -- name of file to open
+ """
+ if self.__base_url:
+ filename = basejoin(self.__base_url,filename)
+ file = open(filename, 'rb')
+ try:
+ schema = self.loadFromStream(file, filename)
+ finally:
+ file.close()
+
+ return schema
+
+
+class SchemaError(Exception):
+ pass
+
+class NoSchemaLocationWarning(Exception):
+ pass
+
+
+###########################
+# DOM Utility Adapters
+##########################
+class DOMAdapterInterface:
+ def hasattr(self, attr, ns=None):
+ """return true if node has attribute
+ attr -- attribute to check for
+ ns -- namespace of attribute, by default None
+ """
+ raise NotImplementedError, 'adapter method not implemented'
+
+ def getContentList(self, *contents):
+ """returns an ordered list of child nodes
+ *contents -- list of node names to return
+ """
+ raise NotImplementedError, 'adapter method not implemented'
+
+ def setAttributeDictionary(self, attributes):
+ """set attribute dictionary
+ """
+ raise NotImplementedError, 'adapter method not implemented'
+
+ def getAttributeDictionary(self):
+ """returns a dict of node's attributes
+ """
+ raise NotImplementedError, 'adapter method not implemented'
+
+ def getNamespace(self, prefix):
+ """returns namespace referenced by prefix.
+ """
+ raise NotImplementedError, 'adapter method not implemented'
+
+ def getTagName(self):
+ """returns tagName of node
+ """
+ raise NotImplementedError, 'adapter method not implemented'
+
+
+ def getParentNode(self):
+ """returns parent element in DOMAdapter or None
+ """
+ raise NotImplementedError, 'adapter method not implemented'
+
+ def loadDocument(self, file):
+ """load a Document from a file object
+ file --
+ """
+ raise NotImplementedError, 'adapter method not implemented'
+
+ def loadFromURL(self, url):
+ """load a Document from an url
+ url -- URL to dereference
+ """
+ raise NotImplementedError, 'adapter method not implemented'
+
+
+class DOMAdapter(DOMAdapterInterface):
+ """Adapter for ZSI.Utility.DOM
+ """
+ def __init__(self, node=None):
+ """Reset all instance variables.
+ element -- DOM document, node, or None
+ """
+ if hasattr(node, 'documentElement'):
+ self.__node = node.documentElement
+ else:
+ self.__node = node
+ self.__attributes = None
+
+ def getNode(self):
+ return self.__node
+
+ def hasattr(self, attr, ns=None):
+ """attr -- attribute
+ ns -- optional namespace, None means unprefixed attribute.
+ """
+ if not self.__attributes:
+ self.setAttributeDictionary()
+ if ns:
+ return self.__attributes.get(ns,{}).has_key(attr)
+ return self.__attributes.has_key(attr)
+
+ def getContentList(self, *contents):
+ nodes = []
+ ELEMENT_NODE = self.__node.ELEMENT_NODE
+ for child in DOM.getElements(self.__node, None):
+ if child.nodeType == ELEMENT_NODE and\
+ SplitQName(child.tagName)[1] in contents:
+ nodes.append(child)
+ return map(self.__class__, nodes)
+
+ def setAttributeDictionary(self):
+ self.__attributes = {}
+ for v in self.__node._attrs.values():
+ self.__attributes[v.nodeName] = v.nodeValue
+
+ def getAttributeDictionary(self):
+ if not self.__attributes:
+ self.setAttributeDictionary()
+ return self.__attributes
+
+ def getTagName(self):
+ return self.__node.tagName
+
+ def getParentNode(self):
+ if self.__node.parentNode.nodeType == self.__node.ELEMENT_NODE:
+ return DOMAdapter(self.__node.parentNode)
+ return None
+
+ def getNamespace(self, prefix):
+ """prefix -- deference namespace prefix in node's context.
+ Ascends parent nodes until found.
+ """
+ namespace = None
+ if prefix == 'xmlns':
+ namespace = DOM.findDefaultNS(prefix, self.__node)
+ else:
+ try:
+ namespace = DOM.findNamespaceURI(prefix, self.__node)
+ except DOMException, ex:
+ if prefix != 'xml':
+ raise SchemaError, '%s namespace not declared for %s'\
+ %(prefix, self.__node._get_tagName())
+ namespace = XMLNS.XML
+ return namespace
+
+ def loadDocument(self, file):
+ self.__node = DOM.loadDocument(file)
+ if hasattr(self.__node, 'documentElement'):
+ self.__node = self.__node.documentElement
+
+ def loadFromURL(self, url):
+ self.__node = DOM.loadFromURL(url)
+ if hasattr(self.__node, 'documentElement'):
+ self.__node = self.__node.documentElement
+
+
+class XMLBase:
+ """ These class variables are for string indentation.
+ """
+ tag = None
+ __indent = 0
+ __rlock = RLock()
+
+ def __str__(self):
+ XMLBase.__rlock.acquire()
+ XMLBase.__indent += 1
+ tmp = "<" + str(self.__class__) + '>\n'
+ for k,v in self.__dict__.items():
+ tmp += "%s* %s = %s\n" %(XMLBase.__indent*' ', k, v)
+ XMLBase.__indent -= 1
+ XMLBase.__rlock.release()
+ return tmp
+
+
+"""Marker Interface: can determine something about an instances properties by using
+ the provided convenience functions.
+
+"""
+class DefinitionMarker:
+ """marker for definitions
+ """
+ pass
+
+class DeclarationMarker:
+ """marker for declarations
+ """
+ pass
+
+class AttributeMarker:
+ """marker for attributes
+ """
+ pass
+
+class AttributeGroupMarker:
+ """marker for attribute groups
+ """
+ pass
+
+class WildCardMarker:
+ """marker for wildcards
+ """
+ pass
+
+class ElementMarker:
+ """marker for wildcards
+ """
+ pass
+
+class ReferenceMarker:
+ """marker for references
+ """
+ pass
+
+class ModelGroupMarker:
+ """marker for model groups
+ """
+ pass
+
+class AllMarker(ModelGroupMarker):
+ """marker for all model group
+ """
+ pass
+
+class ChoiceMarker(ModelGroupMarker):
+ """marker for choice model group
+ """
+ pass
+
+class SequenceMarker(ModelGroupMarker):
+ """marker for sequence model group
+ """
+ pass
+
+class ExtensionMarker:
+ """marker for extensions
+ """
+ pass
+
+class RestrictionMarker:
+ """marker for restrictions
+ """
+ facets = ['enumeration', 'length', 'maxExclusive', 'maxInclusive',\
+ 'maxLength', 'minExclusive', 'minInclusive', 'minLength',\
+ 'pattern', 'fractionDigits', 'totalDigits', 'whiteSpace']
+
+class SimpleMarker:
+ """marker for simple type information
+ """
+ pass
+
+class ListMarker:
+ """marker for simple type list
+ """
+ pass
+
+class UnionMarker:
+ """marker for simple type Union
+ """
+ pass
+
+
+class ComplexMarker:
+ """marker for complex type information
+ """
+ pass
+
+class LocalMarker:
+ """marker for complex type information
+ """
+ pass
+
+
+class MarkerInterface:
+ def isDefinition(self):
+ return isinstance(self, DefinitionMarker)
+
+ def isDeclaration(self):
+ return isinstance(self, DeclarationMarker)
+
+ def isAttribute(self):
+ return isinstance(self, AttributeMarker)
+
+ def isAttributeGroup(self):
+ return isinstance(self, AttributeGroupMarker)
+
+ def isElement(self):
+ return isinstance(self, ElementMarker)
+
+ def isReference(self):
+ return isinstance(self, ReferenceMarker)
+
+ def isWildCard(self):
+ return isinstance(self, WildCardMarker)
+
+ def isModelGroup(self):
+ return isinstance(self, ModelGroupMarker)
+
+ def isAll(self):
+ return isinstance(self, AllMarker)
+
+ def isChoice(self):
+ return isinstance(self, ChoiceMarker)
+
+ def isSequence(self):
+ return isinstance(self, SequenceMarker)
+
+ def isExtension(self):
+ return isinstance(self, ExtensionMarker)
+
+ def isRestriction(self):
+ return isinstance(self, RestrictionMarker)
+
+ def isSimple(self):
+ return isinstance(self, SimpleMarker)
+
+ def isComplex(self):
+ return isinstance(self, ComplexMarker)
+
+ def isLocal(self):
+ return isinstance(self, LocalMarker)
+
+ def isList(self):
+ return isinstance(self, ListMarker)
+
+ def isUnion(self):
+ return isinstance(self, UnionMarker)
+
+
+##########################################################
+# Schema Components
+#########################################################
+class XMLSchemaComponent(XMLBase, MarkerInterface):
+ """
+ class variables:
+ required -- list of required attributes
+ attributes -- dict of default attribute values, including None.
+ Value can be a function for runtime dependencies.
+ contents -- dict of namespace keyed content lists.
+ 'xsd' content of xsd namespace.
+ xmlns_key -- key for declared xmlns namespace.
+ xmlns -- xmlns is special prefix for namespace dictionary
+ xml -- special xml prefix for xml namespace.
+ """
+ required = []
+ attributes = {}
+ contents = {}
+ xmlns_key = ''
+ xmlns = 'xmlns'
+ xml = 'xml'
+
+ def __init__(self, parent=None):
+ """parent -- parent instance
+ instance variables:
+ attributes -- dictionary of node's attributes
+ """
+ self.attributes = None
+ self._parent = parent
+ if self._parent:
+ self._parent = weakref.ref(parent)
+
+ if not self.__class__ == XMLSchemaComponent\
+ and not (type(self.__class__.required) == type(XMLSchemaComponent.required)\
+ and type(self.__class__.attributes) == type(XMLSchemaComponent.attributes)\
+ and type(self.__class__.contents) == type(XMLSchemaComponent.contents)):
+ raise RuntimeError, 'Bad type for a class variable in %s' %self.__class__
+
+ def getItemTrace(self):
+ """Returns a node trace up to the <schema> item.
+ """
+ item, path, name, ref = self, [], 'name', 'ref'
+ while not isinstance(item,XMLSchema) and not isinstance(item,WSDLToolsAdapter):
+ attr = item.getAttribute(name)
+ if not attr:
+ attr = item.getAttribute(ref)
+ if not attr:
+ path.append('<%s>' %(item.tag))
+ else:
+ path.append('<%s ref="%s">' %(item.tag, attr))
+ else:
+ path.append('<%s name="%s">' %(item.tag,attr))
+
+ item = item._parent()
+ try:
+ tns = item.getTargetNamespace()
+ except:
+ tns = ''
+ path.append('<%s targetNamespace="%s">' %(item.tag, tns))
+ path.reverse()
+ return ''.join(path)
+
+ def getTargetNamespace(self):
+ """return targetNamespace
+ """
+ parent = self
+ targetNamespace = 'targetNamespace'
+ tns = self.attributes.get(targetNamespace)
+ while not tns and parent and parent._parent is not None:
+ parent = parent._parent()
+ tns = parent.attributes.get(targetNamespace)
+ return tns or ''
+
+ def getAttributeDeclaration(self, attribute):
+ """attribute -- attribute with a QName value (eg. type).
+ collection -- check types collection in parent Schema instance
+ """
+ return self.getQNameAttribute(ATTRIBUTES, attribute)
+
+ def getAttributeGroup(self, attribute):
+ """attribute -- attribute with a QName value (eg. type).
+ collection -- check types collection in parent Schema instance
+ """
+ return self.getQNameAttribute(ATTRIBUTE_GROUPS, attribute)
+
+ def getTypeDefinition(self, attribute):
+ """attribute -- attribute with a QName value (eg. type).
+ collection -- check types collection in parent Schema instance
+ """
+ return self.getQNameAttribute(TYPES, attribute)
+
+ def getElementDeclaration(self, attribute):
+ """attribute -- attribute with a QName value (eg. element).
+ collection -- check elements collection in parent Schema instance.
+ """
+ return self.getQNameAttribute(ELEMENTS, attribute)
+
+ def getModelGroup(self, attribute):
+ """attribute -- attribute with a QName value (eg. ref).
+ collection -- check model_group collection in parent Schema instance.
+ """
+ return self.getQNameAttribute(MODEL_GROUPS, attribute)
+
+ def getQNameAttribute(self, collection, attribute):
+ """returns object instance representing QName --> (namespace,name),
+ or if does not exist return None.
+ attribute -- an information item attribute, with a QName value.
+ collection -- collection in parent Schema instance to search.
+ """
+ tdc = self.getAttributeQName(attribute)
+ if not tdc:
+ return
+
+ obj = self.getSchemaItem(collection, tdc.getTargetNamespace(), tdc.getName())
+ if obj:
+ return obj
+
+# raise SchemaError, 'No schema item "%s" in collection %s' %(tdc, collection)
+ return
+
+ def getSchemaItem(self, collection, namespace, name):
+ """returns object instance representing namespace, name,
+ or if does not exist return None if built-in, else
+ raise SchemaError.
+
+ namespace -- namespace item defined in.
+ name -- name of item.
+ collection -- collection in parent Schema instance to search.
+ """
+ parent = GetSchema(self)
+ if parent.targetNamespace == namespace:
+ try:
+ obj = getattr(parent, collection)[name]
+ except KeyError, ex:
+ raise KeyError, 'targetNamespace(%s) collection(%s) has no item(%s)'\
+ %(namespace, collection, name)
+
+ return obj
+
+ if not parent.imports.has_key(namespace):
+ if namespace in BUILT_IN_NAMESPACES:
+ # built-in just return
+ # WARNING: expecting import if "redefine" or add to built-in namespace.
+ return
+
+ raise SchemaError, 'schema "%s" does not import namespace "%s"' %(
+ parent.targetNamespace, namespace)
+
+ # Lazy Eval
+ schema = parent.imports[namespace]
+ if not isinstance(schema, XMLSchema):
+ schema = schema.getSchema()
+ if schema is not None:
+ parent.imports[namespace] = schema
+
+ if schema is None:
+ if namespace in BUILT_IN_NAMESPACES:
+ # built-in just return
+ return
+
+ raise SchemaError, 'no schema instance for imported namespace (%s).'\
+ %(namespace)
+
+ if not isinstance(schema, XMLSchema):
+ raise TypeError, 'expecting XMLSchema instance not "%r"' %schema
+
+ try:
+ obj = getattr(schema, collection)[name]
+ except KeyError, ex:
+ raise KeyError, 'targetNamespace(%s) collection(%s) has no item(%s)'\
+ %(namespace, collection, name)
+
+ return obj
+
+ def getXMLNS(self, prefix=None):
+ """deference prefix or by default xmlns, returns namespace.
+ """
+ if prefix == XMLSchemaComponent.xml:
+ return XMLNS.XML
+ parent = self
+ ns = self.attributes[XMLSchemaComponent.xmlns].get(prefix or\
+ XMLSchemaComponent.xmlns_key)
+ while not ns:
+ parent = parent._parent()
+ ns = parent.attributes[XMLSchemaComponent.xmlns].get(prefix or\
+ XMLSchemaComponent.xmlns_key)
+ if not ns and isinstance(parent, WSDLToolsAdapter):
+ if prefix is None:
+ return ''
+ raise SchemaError, 'unknown prefix %s' %prefix
+ return ns
+
+ def getAttribute(self, attribute):
+ """return requested attribute value or None
+ """
+ if type(attribute) in (list, tuple):
+ if len(attribute) != 2:
+ raise LookupError, 'To access attributes must use name or (namespace,name)'
+
+ ns_dict = self.attributes.get(attribute[0])
+ if ns_dict is None:
+ return None
+
+ return ns_dict.get(attribute[1])
+
+ return self.attributes.get(attribute)
+
+ def getAttributeQName(self, attribute):
+ """return requested attribute value as (namespace,name) or None
+ """
+ qname = self.getAttribute(attribute)
+ if isinstance(qname, TypeDescriptionComponent) is True:
+ return qname
+ if qname is None:
+ return None
+
+ prefix,ncname = SplitQName(qname)
+ namespace = self.getXMLNS(prefix)
+ return TypeDescriptionComponent((namespace,ncname))
+
+ def getAttributeName(self):
+ """return attribute name or None
+ """
+ return self.getAttribute('name')
+
+ def setAttributes(self, node):
+ """Sets up attribute dictionary, checks for required attributes and
+ sets default attribute values. attr is for default attribute values
+ determined at runtime.
+
+ structure of attributes dictionary
+ ['xmlns'][xmlns_key] -- xmlns namespace
+ ['xmlns'][prefix] -- declared namespace prefix
+ [namespace][prefix] -- attributes declared in a namespace
+ [attribute] -- attributes w/o prefix, default namespaces do
+ not directly apply to attributes, ie Name can't collide
+ with QName.
+ """
+ self.attributes = {XMLSchemaComponent.xmlns:{}}
+ for k,v in node.getAttributeDictionary().items():
+ prefix,value = SplitQName(k)
+ if value == XMLSchemaComponent.xmlns:
+ self.attributes[value][prefix or XMLSchemaComponent.xmlns_key] = v
+ elif prefix:
+ ns = node.getNamespace(prefix)
+ if not ns:
+ raise SchemaError, 'no namespace for attribute prefix %s'\
+ %prefix
+ if not self.attributes.has_key(ns):
+ self.attributes[ns] = {}
+ elif self.attributes[ns].has_key(value):
+ raise SchemaError, 'attribute %s declared multiple times in %s'\
+ %(value, ns)
+ self.attributes[ns][value] = v
+ elif not self.attributes.has_key(value):
+ self.attributes[value] = v
+ else:
+ raise SchemaError, 'attribute %s declared multiple times' %value
+
+ if not isinstance(self, WSDLToolsAdapter):
+ self.__checkAttributes()
+ self.__setAttributeDefaults()
+
+ #set QNames
+ for k in ['type', 'element', 'base', 'ref', 'substitutionGroup', 'itemType']:
+ if self.attributes.has_key(k):
+ prefix, value = SplitQName(self.attributes.get(k))
+ self.attributes[k] = \
+ TypeDescriptionComponent((self.getXMLNS(prefix), value))
+
+ #Union, memberTypes is a whitespace separated list of QNames
+ for k in ['memberTypes']:
+ if self.attributes.has_key(k):
+ qnames = self.attributes[k]
+ self.attributes[k] = []
+ for qname in qnames.split():
+ prefix, value = SplitQName(qname)
+ self.attributes['memberTypes'].append(\
+ TypeDescriptionComponent(\
+ (self.getXMLNS(prefix), value)))
+
+ def getContents(self, node):
+ """retrieve xsd contents
+ """
+ return node.getContentList(*self.__class__.contents['xsd'])
+
+ def __setAttributeDefaults(self):
+ """Looks for default values for unset attributes. If
+ class variable representing attribute is None, then
+ it must be defined as an instance variable.
+ """
+ for k,v in self.__class__.attributes.items():
+ if v is not None and self.attributes.has_key(k) is False:
+ if isinstance(v, types.FunctionType):
+ self.attributes[k] = v(self)
+ else:
+ self.attributes[k] = v
+
+ def __checkAttributes(self):
+ """Checks that required attributes have been defined,
+ attributes w/default cannot be required. Checks
+ all defined attributes are legal, attribute
+ references are not subject to this test.
+ """
+ for a in self.__class__.required:
+ if not self.attributes.has_key(a):
+ raise SchemaError,\
+ 'class instance %s, missing required attribute %s'\
+ %(self.__class__, a)
+ for a,v in self.attributes.items():
+ # attribute #other, ie. not in empty namespace
+ if type(v) is dict:
+ continue
+
+ # predefined prefixes xmlns, xml
+ if a in (XMLSchemaComponent.xmlns, XMLNS.XML):
+ continue
+
+ if (a not in self.__class__.attributes.keys()) and not\
+ (self.isAttribute() and self.isReference()):
+ raise SchemaError, '%s, unknown attribute(%s,%s)' \
+ %(self.getItemTrace(), a, self.attributes[a])
+
+
+class WSDLToolsAdapter(XMLSchemaComponent):
+ """WSDL Adapter to grab the attributes from the wsdl document node.
+ """
+ attributes = {'name':None, 'targetNamespace':None}
+ tag = 'definitions'
+
+ def __init__(self, wsdl):
+ XMLSchemaComponent.__init__(self, parent=wsdl)
+ self.setAttributes(DOMAdapter(wsdl.document))
+
+ def getImportSchemas(self):
+ """returns WSDLTools.WSDL types Collection
+ """
+ return self._parent().types
+
+
+class Notation(XMLSchemaComponent):
+ """<notation>
+ parent:
+ schema
+ attributes:
+ id -- ID
+ name -- NCName, Required
+ public -- token, Required
+ system -- anyURI
+ contents:
+ annotation?
+ """
+ required = ['name', 'public']
+ attributes = {'id':None, 'name':None, 'public':None, 'system':None}
+ contents = {'xsd':('annotation')}
+ tag = 'notation'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+
+class Annotation(XMLSchemaComponent):
+ """<annotation>
+ parent:
+ all,any,anyAttribute,attribute,attributeGroup,choice,complexContent,
+ complexType,element,extension,field,group,import,include,key,keyref,
+ list,notation,redefine,restriction,schema,selector,simpleContent,
+ simpleType,union,unique
+ attributes:
+ id -- ID
+ contents:
+ (documentation | appinfo)*
+ """
+ attributes = {'id':None}
+ contents = {'xsd':('documentation', 'appinfo')}
+ tag = 'annotation'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.content = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ content = []
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component == 'documentation':
+ #print_debug('class %s, documentation skipped' %self.__class__, 5)
+ continue
+ elif component == 'appinfo':
+ #print_debug('class %s, appinfo skipped' %self.__class__, 5)
+ continue
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ self.content = tuple(content)
+
+
+ class Documentation(XMLSchemaComponent):
+ """<documentation>
+ parent:
+ annotation
+ attributes:
+ source, anyURI
+ xml:lang, language
+ contents:
+ mixed, any
+ """
+ attributes = {'source':None, 'xml:lang':None}
+ contents = {'xsd':('mixed', 'any')}
+ tag = 'documentation'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.content = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ content = []
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component == 'mixed':
+ #print_debug('class %s, mixed skipped' %self.__class__, 5)
+ continue
+ elif component == 'any':
+ #print_debug('class %s, any skipped' %self.__class__, 5)
+ continue
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ self.content = tuple(content)
+
+
+ class Appinfo(XMLSchemaComponent):
+ """<appinfo>
+ parent:
+ annotation
+ attributes:
+ source, anyURI
+ contents:
+ mixed, any
+ """
+ attributes = {'source':None, 'anyURI':None}
+ contents = {'xsd':('mixed', 'any')}
+ tag = 'appinfo'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.content = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ content = []
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component == 'mixed':
+ #print_debug('class %s, mixed skipped' %self.__class__, 5)
+ continue
+ elif component == 'any':
+ #print_debug('class %s, any skipped' %self.__class__, 5)
+ continue
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ self.content = tuple(content)
+
+
+class XMLSchemaFake:
+ # This is temporary, for the benefit of WSDL until the real thing works.
+ def __init__(self, element):
+ self.targetNamespace = DOM.getAttr(element, 'targetNamespace')
+ self.element = element
+
+class XMLSchema(XMLSchemaComponent):
+ """A schema is a collection of schema components derived from one
+ or more schema documents, that is, one or more <schema> element
+ information items. It represents the abstract notion of a schema
+ rather than a single schema document (or other representation).
+
+ <schema>
+ parent:
+ ROOT
+ attributes:
+ id -- ID
+ version -- token
+ xml:lang -- language
+ targetNamespace -- anyURI
+ attributeFormDefault -- 'qualified' | 'unqualified', 'unqualified'
+ elementFormDefault -- 'qualified' | 'unqualified', 'unqualified'
+ blockDefault -- '#all' | list of
+ ('substitution | 'extension' | 'restriction')
+ finalDefault -- '#all' | list of
+ ('extension' | 'restriction' | 'list' | 'union')
+
+ contents:
+ ((include | import | redefine | annotation)*,
+ (attribute, attributeGroup, complexType, element, group,
+ notation, simpleType)*, annotation*)*
+
+
+ attributes -- schema attributes
+ imports -- import statements
+ includes -- include statements
+ redefines --
+ types -- global simpleType, complexType definitions
+ elements -- global element declarations
+ attr_decl -- global attribute declarations
+ attr_groups -- attribute Groups
+ model_groups -- model Groups
+ notations -- global notations
+ """
+ attributes = {'id':None,
+ 'version':None,
+ 'xml:lang':None,
+ 'targetNamespace':None,
+ 'attributeFormDefault':'unqualified',
+ 'elementFormDefault':'unqualified',
+ 'blockDefault':None,
+ 'finalDefault':None}
+ contents = {'xsd':('include', 'import', 'redefine', 'annotation',
+ 'attribute', 'attributeGroup', 'complexType',
+ 'element', 'group', 'notation', 'simpleType',
+ 'annotation')}
+ empty_namespace = ''
+ tag = 'schema'
+
+ def __init__(self, parent=None):
+ """parent --
+ instance variables:
+ targetNamespace -- schema's declared targetNamespace, or empty string.
+ _imported_schemas -- namespace keyed dict of schema dependencies, if
+ a schema is provided instance will not resolve import statement.
+ _included_schemas -- schemaLocation keyed dict of component schemas,
+ if schema is provided instance will not resolve include statement.
+ _base_url -- needed for relative URLs support, only works with URLs
+ relative to initial document.
+ includes -- collection of include statements
+ imports -- collection of import statements
+ elements -- collection of global element declarations
+ types -- collection of global type definitions
+ attr_decl -- collection of global attribute declarations
+ attr_groups -- collection of global attribute group definitions
+ model_groups -- collection of model group definitions
+ notations -- collection of notations
+
+ """
+ self.__node = None
+ self.targetNamespace = None
+ XMLSchemaComponent.__init__(self, parent)
+ f = lambda k: k.attributes['name']
+ ns = lambda k: k.attributes['namespace']
+ sl = lambda k: k.attributes['schemaLocation']
+ self.includes = Collection(self, key=sl)
+ self.imports = Collection(self, key=ns)
+ self.elements = Collection(self, key=f)
+ self.types = Collection(self, key=f)
+ self.attr_decl = Collection(self, key=f)
+ self.attr_groups = Collection(self, key=f)
+ self.model_groups = Collection(self, key=f)
+ self.notations = Collection(self, key=f)
+
+ self._imported_schemas = {}
+ self._included_schemas = {}
+ self._base_url = None
+
+ def getNode(self):
+ """
+ Interacting with the underlying DOM tree.
+ """
+ return self.__node
+
+ def addImportSchema(self, schema):
+ """for resolving import statements in Schema instance
+ schema -- schema instance
+ _imported_schemas
+ """
+ if not isinstance(schema, XMLSchema):
+ raise TypeError, 'expecting a Schema instance'
+ if schema.targetNamespace != self.targetNamespace:
+ self._imported_schemas[schema.targetNamespace] = schema
+ else:
+ raise SchemaError, 'import schema bad targetNamespace'
+
+ def addIncludeSchema(self, schemaLocation, schema):
+ """for resolving include statements in Schema instance
+ schemaLocation -- schema location
+ schema -- schema instance
+ _included_schemas
+ """
+ if not isinstance(schema, XMLSchema):
+ raise TypeError, 'expecting a Schema instance'
+ if not schema.targetNamespace or\
+ schema.targetNamespace == self.targetNamespace:
+ self._included_schemas[schemaLocation] = schema
+ else:
+ raise SchemaError, 'include schema bad targetNamespace'
+
+ def setImportSchemas(self, schema_dict):
+ """set the import schema dictionary, which is used to
+ reference depedent schemas.
+ """
+ self._imported_schemas = schema_dict
+
+ def getImportSchemas(self):
+ """get the import schema dictionary, which is used to
+ reference depedent schemas.
+ """
+ return self._imported_schemas
+
+ def getSchemaNamespacesToImport(self):
+ """returns tuple of namespaces the schema instance has declared
+ itself to be depedent upon.
+ """
+ return tuple(self.includes.keys())
+
+ def setIncludeSchemas(self, schema_dict):
+ """set the include schema dictionary, which is keyed with
+ schemaLocation (uri).
+ This is a means of providing
+ schemas to the current schema for content inclusion.
+ """
+ self._included_schemas = schema_dict
+
+ def getIncludeSchemas(self):
+ """get the include schema dictionary, which is keyed with
+ schemaLocation (uri).
+ """
+ return self._included_schemas
+
+ def getBaseUrl(self):
+ """get base url, used for normalizing all relative uri's
+ """
+ return self._base_url
+
+ def setBaseUrl(self, url):
+ """set base url, used for normalizing all relative uri's
+ """
+ self._base_url = url
+
+ def getElementFormDefault(self):
+ """return elementFormDefault attribute
+ """
+ return self.attributes.get('elementFormDefault')
+
+ def isElementFormDefaultQualified(self):
+ return self.attributes.get('elementFormDefault') == 'qualified'
+
+ def getAttributeFormDefault(self):
+ """return attributeFormDefault attribute
+ """
+ return self.attributes.get('attributeFormDefault')
+
+ def getBlockDefault(self):
+ """return blockDefault attribute
+ """
+ return self.attributes.get('blockDefault')
+
+ def getFinalDefault(self):
+ """return finalDefault attribute
+ """
+ return self.attributes.get('finalDefault')
+
+ def load(self, node, location=None):
+ self.__node = node
+
+ pnode = node.getParentNode()
+ if pnode:
+ pname = SplitQName(pnode.getTagName())[1]
+ if pname == 'types':
+ attributes = {}
+ self.setAttributes(pnode)
+ attributes.update(self.attributes)
+ self.setAttributes(node)
+ for k,v in attributes['xmlns'].items():
+ if not self.attributes['xmlns'].has_key(k):
+ self.attributes['xmlns'][k] = v
+ else:
+ self.setAttributes(node)
+ else:
+ self.setAttributes(node)
+
+ self.targetNamespace = self.getTargetNamespace()
+ for childNode in self.getContents(node):
+ component = SplitQName(childNode.getTagName())[1]
+
+ if component == 'include':
+ tp = self.__class__.Include(self)
+ tp.fromDom(childNode)
+
+ sl = tp.attributes['schemaLocation']
+ schema = tp.getSchema()
+
+ if not self.getIncludeSchemas().has_key(sl):
+ self.addIncludeSchema(sl, schema)
+
+ self.includes[sl] = tp
+
+ pn = childNode.getParentNode().getNode()
+ pn.removeChild(childNode.getNode())
+ for child in schema.getNode().getNode().childNodes:
+ pn.appendChild(child.cloneNode(1))
+
+ for collection in ['imports','elements','types',
+ 'attr_decl','attr_groups','model_groups',
+ 'notations']:
+ for k,v in getattr(schema,collection).items():
+ if not getattr(self,collection).has_key(k):
+ v._parent = weakref.ref(self)
+ getattr(self,collection)[k] = v
+ else:
+ warnings.warn("Not keeping schema component.")
+
+ elif component == 'import':
+ slocd = SchemaReader.namespaceToSchema
+ tp = self.__class__.Import(self)
+ tp.fromDom(childNode)
+ import_ns = tp.getAttribute('namespace') or\
+ self.__class__.empty_namespace
+ schema = slocd.get(import_ns)
+ if schema is None:
+ schema = XMLSchema()
+ slocd[import_ns] = schema
+ try:
+ tp.loadSchema(schema)
+ except NoSchemaLocationWarning, ex:
+ # Dependency declaration, hopefully implementation
+ # is aware of this namespace (eg. SOAP,WSDL,?)
+ print "IMPORT: ", import_ns
+ print ex
+ del slocd[import_ns]
+ continue
+ except SchemaError, ex:
+ #warnings.warn(\
+ # '<import namespace="%s" schemaLocation=?>, %s'\
+ # %(import_ns, 'failed to load schema instance')
+ #)
+ print ex
+ del slocd[import_ns]
+ class _LazyEvalImport(str):
+ '''Lazy evaluation of import, replace entry in self.imports.'''
+ #attributes = dict(namespace=import_ns)
+ def getSchema(namespace):
+ schema = slocd.get(namespace)
+ if schema is None:
+ parent = self._parent()
+ wstypes = parent
+ if isinstance(parent, WSDLToolsAdapter):
+ wstypes = parent.getImportSchemas()
+ schema = wstypes.get(namespace)
+ if isinstance(schema, XMLSchema):
+ self.imports[namespace] = schema
+ return schema
+
+ return None
+
+ self.imports[import_ns] = _LazyEvalImport(import_ns)
+ continue
+ else:
+ tp._schema = schema
+
+ if self.getImportSchemas().has_key(import_ns):
+ warnings.warn(\
+ 'Detected multiple imports of the namespace "%s" '\
+ %import_ns)
+
+ self.addImportSchema(schema)
+ # spec says can have multiple imports of same namespace
+ # but purpose of import is just dependency declaration.
+ self.imports[import_ns] = tp
+
+ elif component == 'redefine':
+ warnings.warn('redefine is ignored')
+ elif component == 'annotation':
+ warnings.warn('annotation is ignored')
+ elif component == 'attribute':
+ tp = AttributeDeclaration(self)
+ tp.fromDom(childNode)
+ self.attr_decl[tp.getAttribute('name')] = tp
+ elif component == 'attributeGroup':
+ tp = AttributeGroupDefinition(self)
+ tp.fromDom(childNode)
+ self.attr_groups[tp.getAttribute('name')] = tp
+ elif component == 'element':
+ tp = ElementDeclaration(self)
+ tp.fromDom(childNode)
+ self.elements[tp.getAttribute('name')] = tp
+ elif component == 'group':
+ tp = ModelGroupDefinition(self)
+ tp.fromDom(childNode)
+ self.model_groups[tp.getAttribute('name')] = tp
+ elif component == 'notation':
+ tp = Notation(self)
+ tp.fromDom(childNode)
+ self.notations[tp.getAttribute('name')] = tp
+ elif component == 'complexType':
+ tp = ComplexType(self)
+ tp.fromDom(childNode)
+ self.types[tp.getAttribute('name')] = tp
+ elif component == 'simpleType':
+ tp = SimpleType(self)
+ tp.fromDom(childNode)
+ self.types[tp.getAttribute('name')] = tp
+ else:
+ break
+
+ class Import(XMLSchemaComponent):
+ """<import>
+ parent:
+ schema
+ attributes:
+ id -- ID
+ namespace -- anyURI
+ schemaLocation -- anyURI
+ contents:
+ annotation?
+ """
+ attributes = {'id':None,
+ 'namespace':None,
+ 'schemaLocation':None}
+ contents = {'xsd':['annotation']}
+ tag = 'import'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self._schema = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ if self.attributes['namespace'] == self.getTargetNamespace():
+ raise SchemaError, 'namespace of schema and import match'
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+ def getSchema(self):
+ """if schema is not defined, first look for a Schema class instance
+ in parent Schema. Else if not defined resolve schemaLocation
+ and create a new Schema class instance, and keep a hard reference.
+ """
+ if not self._schema:
+ ns = self.attributes['namespace']
+ schema = self._parent().getImportSchemas().get(ns)
+ if not schema and self._parent()._parent:
+ schema = self._parent()._parent().getImportSchemas().get(ns)
+
+ if not schema:
+ url = self.attributes.get('schemaLocation')
+ if not url:
+ raise SchemaError, 'namespace(%s) is unknown' %ns
+ base_url = self._parent().getBaseUrl()
+ reader = SchemaReader(base_url=base_url)
+ reader._imports = self._parent().getImportSchemas()
+ reader._includes = self._parent().getIncludeSchemas()
+ self._schema = reader.loadFromURL(url)
+ return self._schema or schema
+
+ def loadSchema(self, schema):
+ """
+ """
+ base_url = self._parent().getBaseUrl()
+ reader = SchemaReader(base_url=base_url)
+ reader._imports = self._parent().getImportSchemas()
+ reader._includes = self._parent().getIncludeSchemas()
+ self._schema = schema
+
+ if not self.attributes.has_key('schemaLocation'):
+ raise NoSchemaLocationWarning('no schemaLocation attribute in import')
+
+ reader.loadFromURL(self.attributes.get('schemaLocation'), schema)
+
+
+ class Include(XMLSchemaComponent):
+ """<include schemaLocation>
+ parent:
+ schema
+ attributes:
+ id -- ID
+ schemaLocation -- anyURI, required
+ contents:
+ annotation?
+ """
+ required = ['schemaLocation']
+ attributes = {'id':None,
+ 'schemaLocation':None}
+ contents = {'xsd':['annotation']}
+ tag = 'include'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self._schema = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+ def getSchema(self):
+ """if schema is not defined, first look for a Schema class instance
+ in parent Schema. Else if not defined resolve schemaLocation
+ and create a new Schema class instance.
+ """
+ if not self._schema:
+ schema = self._parent()
+ self._schema = schema.getIncludeSchemas().get(\
+ self.attributes['schemaLocation']
+ )
+ if not self._schema:
+ url = self.attributes['schemaLocation']
+ reader = SchemaReader(base_url=schema.getBaseUrl())
+ reader._imports = schema.getImportSchemas()
+ reader._includes = schema.getIncludeSchemas()
+
+ # create schema before loading so chameleon include
+ # will evalute targetNamespace correctly.
+ self._schema = XMLSchema(schema)
+ reader.loadFromURL(url, self._schema)
+
+ return self._schema
+
+
+class AttributeDeclaration(XMLSchemaComponent,\
+ AttributeMarker,\
+ DeclarationMarker):
+ """<attribute name>
+ parent:
+ schema
+ attributes:
+ id -- ID
+ name -- NCName, required
+ type -- QName
+ default -- string
+ fixed -- string
+ contents:
+ annotation?, simpleType?
+ """
+ required = ['name']
+ attributes = {'id':None,
+ 'name':None,
+ 'type':None,
+ 'default':None,
+ 'fixed':None}
+ contents = {'xsd':['annotation','simpleType']}
+ tag = 'attribute'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+
+ def fromDom(self, node):
+ """ No list or union support
+ """
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ elif component == 'simpleType':
+ self.content = AnonymousSimpleType(self)
+ self.content.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+
+class LocalAttributeDeclaration(AttributeDeclaration,\
+ AttributeMarker,\
+ LocalMarker,\
+ DeclarationMarker):
+ """<attribute name>
+ parent:
+ complexType, restriction, extension, attributeGroup
+ attributes:
+ id -- ID
+ name -- NCName, required
+ type -- QName
+ form -- ('qualified' | 'unqualified'), schema.attributeFormDefault
+ use -- ('optional' | 'prohibited' | 'required'), optional
+ default -- string
+ fixed -- string
+ contents:
+ annotation?, simpleType?
+ """
+ required = ['name']
+ attributes = {'id':None,
+ 'name':None,
+ 'type':None,
+ 'form':lambda self: GetSchema(self).getAttributeFormDefault(),
+ 'use':'optional',
+ 'default':None,
+ 'fixed':None}
+ contents = {'xsd':['annotation','simpleType']}
+
+ def __init__(self, parent):
+ AttributeDeclaration.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ elif component == 'simpleType':
+ self.content = AnonymousSimpleType(self)
+ self.content.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+
+class AttributeWildCard(XMLSchemaComponent,\
+ AttributeMarker,\
+ DeclarationMarker,\
+ WildCardMarker):
+ """<anyAttribute>
+ parents:
+ complexType, restriction, extension, attributeGroup
+ attributes:
+ id -- ID
+ namespace -- '##any' | '##other' |
+ (anyURI* | '##targetNamespace' | '##local'), ##any
+ processContents -- 'lax' | 'skip' | 'strict', strict
+ contents:
+ annotation?
+ """
+ attributes = {'id':None,
+ 'namespace':'##any',
+ 'processContents':'strict'}
+ contents = {'xsd':['annotation']}
+ tag = 'anyAttribute'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+
+class AttributeReference(XMLSchemaComponent,\
+ AttributeMarker,\
+ ReferenceMarker):
+ """<attribute ref>
+ parents:
+ complexType, restriction, extension, attributeGroup
+ attributes:
+ id -- ID
+ ref -- QName, required
+ use -- ('optional' | 'prohibited' | 'required'), optional
+ default -- string
+ fixed -- string
+ contents:
+ annotation?
+ """
+ required = ['ref']
+ attributes = {'id':None,
+ 'ref':None,
+ 'use':'optional',
+ 'default':None,
+ 'fixed':None}
+ contents = {'xsd':['annotation']}
+ tag = 'attribute'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+
+ def getAttributeDeclaration(self, attribute='ref'):
+ return XMLSchemaComponent.getAttributeDeclaration(self, attribute)
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+
+class AttributeGroupDefinition(XMLSchemaComponent,\
+ AttributeGroupMarker,\
+ DefinitionMarker):
+ """<attributeGroup name>
+ parents:
+ schema, redefine
+ attributes:
+ id -- ID
+ name -- NCName, required
+ contents:
+ annotation?, (attribute | attributeGroup)*, anyAttribute?
+ """
+ required = ['name']
+ attributes = {'id':None,
+ 'name':None}
+ contents = {'xsd':['annotation', 'attribute', 'attributeGroup', 'anyAttribute']}
+ tag = 'attributeGroup'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.attr_content = None
+
+ def getAttributeContent(self):
+ return self.attr_content
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ content = []
+
+ for indx in range(len(contents)):
+ component = SplitQName(contents[indx].getTagName())[1]
+ if (component == 'annotation') and (not indx):
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(contents[indx])
+ elif component == 'attribute':
+ if contents[indx].hasattr('name'):
+ content.append(LocalAttributeDeclaration(self))
+ elif contents[indx].hasattr('ref'):
+ content.append(AttributeReference(self))
+ else:
+ raise SchemaError, 'Unknown attribute type'
+ content[-1].fromDom(contents[indx])
+ elif component == 'attributeGroup':
+ content.append(AttributeGroupReference(self))
+ content[-1].fromDom(contents[indx])
+ elif component == 'anyAttribute':
+ if len(contents) != indx+1:
+ raise SchemaError, 'anyAttribute is out of order in %s' %self.getItemTrace()
+ content.append(AttributeWildCard(self))
+ content[-1].fromDom(contents[indx])
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(contents[indx].getTagName())
+
+ self.attr_content = tuple(content)
+
+class AttributeGroupReference(XMLSchemaComponent,\
+ AttributeGroupMarker,\
+ ReferenceMarker):
+ """<attributeGroup ref>
+ parents:
+ complexType, restriction, extension, attributeGroup
+ attributes:
+ id -- ID
+ ref -- QName, required
+ contents:
+ annotation?
+ """
+ required = ['ref']
+ attributes = {'id':None,
+ 'ref':None}
+ contents = {'xsd':['annotation']}
+ tag = 'attributeGroup'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+
+ def getAttributeGroup(self, attribute='ref'):
+ """attribute -- attribute with a QName value (eg. type).
+ collection -- check types collection in parent Schema instance
+ """
+ return XMLSchemaComponent.getAttributeGroup(self, attribute)
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+
+
+######################################################
+# Elements
+#####################################################
+class IdentityConstrants(XMLSchemaComponent):
+ """Allow one to uniquely identify nodes in a document and ensure the
+ integrity of references between them.
+
+ attributes -- dictionary of attributes
+ selector -- XPath to selected nodes
+ fields -- list of XPath to key field
+ """
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.selector = None
+ self.fields = None
+ self.annotation = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ fields = []
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component in self.__class__.contents['xsd']:
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ elif component == 'selector':
+ self.selector = self.Selector(self)
+ self.selector.fromDom(i)
+ continue
+ elif component == 'field':
+ fields.append(self.Field(self))
+ fields[-1].fromDom(i)
+ continue
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ self.fields = tuple(fields)
+
+
+ class Constraint(XMLSchemaComponent):
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component in self.__class__.contents['xsd']:
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+ class Selector(Constraint):
+ """<selector xpath>
+ parent:
+ unique, key, keyref
+ attributes:
+ id -- ID
+ xpath -- XPath subset, required
+ contents:
+ annotation?
+ """
+ required = ['xpath']
+ attributes = {'id':None,
+ 'xpath':None}
+ contents = {'xsd':['annotation']}
+ tag = 'selector'
+
+ class Field(Constraint):
+ """<field xpath>
+ parent:
+ unique, key, keyref
+ attributes:
+ id -- ID
+ xpath -- XPath subset, required
+ contents:
+ annotation?
+ """
+ required = ['xpath']
+ attributes = {'id':None,
+ 'xpath':None}
+ contents = {'xsd':['annotation']}
+ tag = 'field'
+
+
+class Unique(IdentityConstrants):
+ """<unique name> Enforce fields are unique w/i a specified scope.
+
+ parent:
+ element
+ attributes:
+ id -- ID
+ name -- NCName, required
+ contents:
+ annotation?, selector, field+
+ """
+ required = ['name']
+ attributes = {'id':None,
+ 'name':None}
+ contents = {'xsd':['annotation', 'selector', 'field']}
+ tag = 'unique'
+
+
+class Key(IdentityConstrants):
+ """<key name> Enforce fields are unique w/i a specified scope, and all
+ field values are present w/i document. Fields cannot
+ be nillable.
+
+ parent:
+ element
+ attributes:
+ id -- ID
+ name -- NCName, required
+ contents:
+ annotation?, selector, field+
+ """
+ required = ['name']
+ attributes = {'id':None,
+ 'name':None}
+ contents = {'xsd':['annotation', 'selector', 'field']}
+ tag = 'key'
+
+
+class KeyRef(IdentityConstrants):
+ """<keyref name refer> Ensure a match between two sets of values in an
+ instance.
+ parent:
+ element
+ attributes:
+ id -- ID
+ name -- NCName, required
+ refer -- QName, required
+ contents:
+ annotation?, selector, field+
+ """
+ required = ['name', 'refer']
+ attributes = {'id':None,
+ 'name':None,
+ 'refer':None}
+ contents = {'xsd':['annotation', 'selector', 'field']}
+ tag = 'keyref'
+
+
+class ElementDeclaration(XMLSchemaComponent,\
+ ElementMarker,\
+ DeclarationMarker):
+ """<element name>
+ parents:
+ schema
+ attributes:
+ id -- ID
+ name -- NCName, required
+ type -- QName
+ default -- string
+ fixed -- string
+ nillable -- boolean, false
+ abstract -- boolean, false
+ substitutionGroup -- QName
+ block -- ('#all' | ('substition' | 'extension' | 'restriction')*),
+ schema.blockDefault
+ final -- ('#all' | ('extension' | 'restriction')*),
+ schema.finalDefault
+ contents:
+ annotation?, (simpleType,complexType)?, (key | keyref | unique)*
+
+ """
+ required = ['name']
+ attributes = {'id':None,
+ 'name':None,
+ 'type':None,
+ 'default':None,
+ 'fixed':None,
+ 'nillable':0,
+ 'abstract':0,
+ 'substitutionGroup':None,
+ 'block':lambda self: self._parent().getBlockDefault(),
+ 'final':lambda self: self._parent().getFinalDefault()}
+ contents = {'xsd':['annotation', 'simpleType', 'complexType', 'key',\
+ 'keyref', 'unique']}
+ tag = 'element'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+ self.constraints = ()
+
+ def isQualified(self):
+ """Global elements are always qualified.
+ """
+ return True
+
+ def getAttribute(self, attribute):
+ """return attribute.
+ If attribute is type and it's None, and no simple or complex content,
+ return the default type "xsd:anyType"
+ """
+ value = XMLSchemaComponent.getAttribute(self, attribute)
+ if attribute != 'type' or value is not None:
+ return value
+
+ if self.content is not None:
+ return None
+
+ parent = self
+ while 1:
+ nsdict = parent.attributes[XMLSchemaComponent.xmlns]
+ for k,v in nsdict.items():
+ if v not in SCHEMA.XSD_LIST: continue
+ return TypeDescriptionComponent((v, 'anyType'))
+
+ if isinstance(parent, WSDLToolsAdapter)\
+ or not hasattr(parent, '_parent'):
+ break
+
+ parent = parent._parent()
+
+ raise SchemaError, 'failed to locate the XSD namespace'
+
+ def getElementDeclaration(self, attribute):
+ raise Warning, 'invalid operation for <%s>' %self.tag
+
+ def getTypeDefinition(self, attribute=None):
+ """If attribute is None, "type" is assumed, return the corresponding
+ representation of the global type definition (TypeDefinition),
+ or the local definition if don't find "type". To maintain backwards
+ compat, if attribute is provided call base class method.
+ """
+ if attribute:
+ return XMLSchemaComponent.getTypeDefinition(self, attribute)
+ gt = XMLSchemaComponent.getTypeDefinition(self, 'type')
+ if gt:
+ return gt
+ return self.content
+
+ def getConstraints(self):
+ return self._constraints
+ def setConstraints(self, constraints):
+ self._constraints = tuple(constraints)
+ constraints = property(getConstraints, setConstraints, None, "tuple of key, keyref, unique constraints")
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ constraints = []
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component in self.__class__.contents['xsd']:
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ elif component == 'simpleType' and not self.content:
+ self.content = AnonymousSimpleType(self)
+ self.content.fromDom(i)
+ elif component == 'complexType' and not self.content:
+ self.content = LocalComplexType(self)
+ self.content.fromDom(i)
+ elif component == 'key':
+ constraints.append(Key(self))
+ constraints[-1].fromDom(i)
+ elif component == 'keyref':
+ constraints.append(KeyRef(self))
+ constraints[-1].fromDom(i)
+ elif component == 'unique':
+ constraints.append(Unique(self))
+ constraints[-1].fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+ self.constraints = constraints
+
+
+class LocalElementDeclaration(ElementDeclaration,\
+ LocalMarker):
+ """<element>
+ parents:
+ all, choice, sequence
+ attributes:
+ id -- ID
+ name -- NCName, required
+ form -- ('qualified' | 'unqualified'), schema.elementFormDefault
+ type -- QName
+ minOccurs -- Whole Number, 1
+ maxOccurs -- (Whole Number | 'unbounded'), 1
+ default -- string
+ fixed -- string
+ nillable -- boolean, false
+ block -- ('#all' | ('extension' | 'restriction')*), schema.blockDefault
+ contents:
+ annotation?, (simpleType,complexType)?, (key | keyref | unique)*
+ """
+ required = ['name']
+ attributes = {'id':None,
+ 'name':None,
+ 'form':lambda self: GetSchema(self).getElementFormDefault(),
+ 'type':None,
+ 'minOccurs':'1',
+ 'maxOccurs':'1',
+ 'default':None,
+ 'fixed':None,
+ 'nillable':0,
+ 'abstract':0,
+ 'block':lambda self: GetSchema(self).getBlockDefault()}
+ contents = {'xsd':['annotation', 'simpleType', 'complexType', 'key',\
+ 'keyref', 'unique']}
+
+ def isQualified(self):
+ """
+Local elements can be qualified or unqualifed according
+ to the attribute form, or the elementFormDefault. By default
+ local elements are unqualified.
+ """
+ form = self.getAttribute('form')
+ if form == 'qualified':
+ return True
+ if form == 'unqualified':
+ return False
+ raise SchemaError, 'Bad form (%s) for element: %s' %(form, self.getItemTrace())
+
+
+class ElementReference(XMLSchemaComponent,\
+ ElementMarker,\
+ ReferenceMarker):
+ """<element ref>
+ parents:
+ all, choice, sequence
+ attributes:
+ id -- ID
+ ref -- QName, required
+ minOccurs -- Whole Number, 1
+ maxOccurs -- (Whole Number | 'unbounded'), 1
+ contents:
+ annotation?
+ """
+ required = ['ref']
+ attributes = {'id':None,
+ 'ref':None,
+ 'minOccurs':'1',
+ 'maxOccurs':'1'}
+ contents = {'xsd':['annotation']}
+ tag = 'element'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+
+ def getElementDeclaration(self, attribute=None):
+ """If attribute is None, "ref" is assumed, return the corresponding
+ representation of the global element declaration (ElementDeclaration),
+ To maintain backwards compat, if attribute is provided call base class method.
+ """
+ if attribute:
+ return XMLSchemaComponent.getElementDeclaration(self, attribute)
+ return XMLSchemaComponent.getElementDeclaration(self, 'ref')
+
+ def fromDom(self, node):
+ self.annotation = None
+ self.setAttributes(node)
+ for i in self.getContents(node):
+ component = SplitQName(i.getTagName())[1]
+ if component in self.__class__.contents['xsd']:
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+
+class ElementWildCard(LocalElementDeclaration, WildCardMarker):
+ """<any>
+ parents:
+ choice, sequence
+ attributes:
+ id -- ID
+ minOccurs -- Whole Number, 1
+ maxOccurs -- (Whole Number | 'unbounded'), 1
+ namespace -- '##any' | '##other' |
+ (anyURI* | '##targetNamespace' | '##local'), ##any
+ processContents -- 'lax' | 'skip' | 'strict', strict
+ contents:
+ annotation?
+ """
+ required = []
+ attributes = {'id':None,
+ 'minOccurs':'1',
+ 'maxOccurs':'1',
+ 'namespace':'##any',
+ 'processContents':'strict'}
+ contents = {'xsd':['annotation']}
+ tag = 'any'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+
+ def isQualified(self):
+ """
+ Global elements are always qualified, but if processContents
+ are not strict could have dynamically generated local elements.
+ """
+ return GetSchema(self).isElementFormDefaultQualified()
+
+ def getAttribute(self, attribute):
+ """return attribute.
+ """
+ return XMLSchemaComponent.getAttribute(self, attribute)
+
+ def getTypeDefinition(self, attribute):
+ raise Warning, 'invalid operation for <%s>' % self.tag
+
+ def fromDom(self, node):
+ self.annotation = None
+ self.setAttributes(node)
+ for i in self.getContents(node):
+ component = SplitQName(i.getTagName())[1]
+ if component in self.__class__.contents['xsd']:
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+
+######################################################
+# Model Groups
+#####################################################
+class Sequence(XMLSchemaComponent,\
+ SequenceMarker):
+ """<sequence>
+ parents:
+ complexType, extension, restriction, group, choice, sequence
+ attributes:
+ id -- ID
+ minOccurs -- Whole Number, 1
+ maxOccurs -- (Whole Number | 'unbounded'), 1
+
+ contents:
+ annotation?, (element | group | choice | sequence | any)*
+ """
+ attributes = {'id':None,
+ 'minOccurs':'1',
+ 'maxOccurs':'1'}
+ contents = {'xsd':['annotation', 'element', 'group', 'choice', 'sequence',\
+ 'any']}
+ tag = 'sequence'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ content = []
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component in self.__class__.contents['xsd']:
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ continue
+ elif component == 'element':
+ if i.hasattr('ref'):
+ content.append(ElementReference(self))
+ else:
+ content.append(LocalElementDeclaration(self))
+ elif component == 'group':
+ content.append(ModelGroupReference(self))
+ elif component == 'choice':
+ content.append(Choice(self))
+ elif component == 'sequence':
+ content.append(Sequence(self))
+ elif component == 'any':
+ content.append(ElementWildCard(self))
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ content[-1].fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ self.content = tuple(content)
+
+
+class All(XMLSchemaComponent,\
+ AllMarker):
+ """<all>
+ parents:
+ complexType, extension, restriction, group
+ attributes:
+ id -- ID
+ minOccurs -- '0' | '1', 1
+ maxOccurs -- '1', 1
+
+ contents:
+ annotation?, element*
+ """
+ attributes = {'id':None,
+ 'minOccurs':'1',
+ 'maxOccurs':'1'}
+ contents = {'xsd':['annotation', 'element']}
+ tag = 'all'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ content = []
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component in self.__class__.contents['xsd']:
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ continue
+ elif component == 'element':
+ if i.hasattr('ref'):
+ content.append(ElementReference(self))
+ else:
+ content.append(LocalElementDeclaration(self))
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ content[-1].fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ self.content = tuple(content)
+
+
+class Choice(XMLSchemaComponent,\
+ ChoiceMarker):
+ """<choice>
+ parents:
+ complexType, extension, restriction, group, choice, sequence
+ attributes:
+ id -- ID
+ minOccurs -- Whole Number, 1
+ maxOccurs -- (Whole Number | 'unbounded'), 1
+
+ contents:
+ annotation?, (element | group | choice | sequence | any)*
+ """
+ attributes = {'id':None,
+ 'minOccurs':'1',
+ 'maxOccurs':'1'}
+ contents = {'xsd':['annotation', 'element', 'group', 'choice', 'sequence',\
+ 'any']}
+ tag = 'choice'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ content = []
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component in self.__class__.contents['xsd']:
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ continue
+ elif component == 'element':
+ if i.hasattr('ref'):
+ content.append(ElementReference(self))
+ else:
+ content.append(LocalElementDeclaration(self))
+ elif component == 'group':
+ content.append(ModelGroupReference(self))
+ elif component == 'choice':
+ content.append(Choice(self))
+ elif component == 'sequence':
+ content.append(Sequence(self))
+ elif component == 'any':
+ content.append(ElementWildCard(self))
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ content[-1].fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ self.content = tuple(content)
+
+
+class ModelGroupDefinition(XMLSchemaComponent,\
+ ModelGroupMarker,\
+ DefinitionMarker):
+ """<group name>
+ parents:
+ redefine, schema
+ attributes:
+ id -- ID
+ name -- NCName, required
+
+ contents:
+ annotation?, (all | choice | sequence)?
+ """
+ required = ['name']
+ attributes = {'id':None,
+ 'name':None}
+ contents = {'xsd':['annotation', 'all', 'choice', 'sequence']}
+ tag = 'group'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component in self.__class__.contents['xsd']:
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ continue
+ elif component == 'all' and not self.content:
+ self.content = All(self)
+ elif component == 'choice' and not self.content:
+ self.content = Choice(self)
+ elif component == 'sequence' and not self.content:
+ self.content = Sequence(self)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ self.content.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+
+class ModelGroupReference(XMLSchemaComponent,\
+ ModelGroupMarker,\
+ ReferenceMarker):
+ """<group ref>
+ parents:
+ choice, complexType, extension, restriction, sequence
+ attributes:
+ id -- ID
+ ref -- NCName, required
+ minOccurs -- Whole Number, 1
+ maxOccurs -- (Whole Number | 'unbounded'), 1
+
+ contents:
+ annotation?
+ """
+ required = ['ref']
+ attributes = {'id':None,
+ 'ref':None,
+ 'minOccurs':'1',
+ 'maxOccurs':'1'}
+ contents = {'xsd':['annotation']}
+ tag = 'group'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+
+ def getModelGroupReference(self):
+ return self.getModelGroup('ref')
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component in self.__class__.contents['xsd']:
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+
+
+class ComplexType(XMLSchemaComponent,\
+ DefinitionMarker,\
+ ComplexMarker):
+ """<complexType name>
+ parents:
+ redefine, schema
+ attributes:
+ id -- ID
+ name -- NCName, required
+ mixed -- boolean, false
+ abstract -- boolean, false
+ block -- ('#all' | ('extension' | 'restriction')*), schema.blockDefault
+ final -- ('#all' | ('extension' | 'restriction')*), schema.finalDefault
+
+ contents:
+ annotation?, (simpleContent | complexContent |
+ ((group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute?))
+ """
+ required = ['name']
+ attributes = {'id':None,
+ 'name':None,
+ 'mixed':0,
+ 'abstract':0,
+ 'block':lambda self: self._parent().getBlockDefault(),
+ 'final':lambda self: self._parent().getFinalDefault()}
+ contents = {'xsd':['annotation', 'simpleContent', 'complexContent',\
+ 'group', 'all', 'choice', 'sequence', 'attribute', 'attributeGroup',\
+ 'anyAttribute', 'any']}
+ tag = 'complexType'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+ self.attr_content = None
+
+ def isMixed(self):
+ m = self.getAttribute('mixed')
+ if m == 0 or m == False:
+ return False
+ if isinstance(m, basestring) is True:
+ if m in ('false', '0'):
+ return False
+ if m in ('true', '1'):
+ return True
+
+ raise SchemaError, 'invalid value for attribute mixed(%s): %s'\
+ %(m, self.getItemTrace())
+
+ def getAttributeContent(self):
+ return self.attr_content
+
+ def getElementDeclaration(self, attribute):
+ raise Warning, 'invalid operation for <%s>' %self.tag
+
+ def getTypeDefinition(self, attribute):
+ raise Warning, 'invalid operation for <%s>' %self.tag
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ indx = 0
+ num = len(contents)
+ if not num:
+ return
+
+ component = SplitQName(contents[indx].getTagName())[1]
+ if component == 'annotation':
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(contents[indx])
+ indx += 1
+ if indx < num:
+ component = SplitQName(contents[indx].getTagName())[1]
+
+ self.content = None
+ if component == 'simpleContent':
+ self.content = self.__class__.SimpleContent(self)
+ self.content.fromDom(contents[indx])
+ elif component == 'complexContent':
+ self.content = self.__class__.ComplexContent(self)
+ self.content.fromDom(contents[indx])
+ else:
+ if component == 'all':
+ self.content = All(self)
+ elif component == 'choice':
+ self.content = Choice(self)
+ elif component == 'sequence':
+ self.content = Sequence(self)
+ elif component == 'group':
+ self.content = ModelGroupReference(self)
+
+ if self.content:
+ self.content.fromDom(contents[indx])
+ indx += 1
+
+ self.attr_content = []
+ while indx < num:
+ component = SplitQName(contents[indx].getTagName())[1]
+ if component == 'attribute':
+ if contents[indx].hasattr('ref'):
+ self.attr_content.append(AttributeReference(self))
+ else:
+ self.attr_content.append(LocalAttributeDeclaration(self))
+ elif component == 'attributeGroup':
+ self.attr_content.append(AttributeGroupReference(self))
+ elif component == 'anyAttribute':
+ self.attr_content.append(AttributeWildCard(self))
+ else:
+ raise SchemaError, 'Unknown component (%s): %s' \
+ %(contents[indx].getTagName(),self.getItemTrace())
+ self.attr_content[-1].fromDom(contents[indx])
+ indx += 1
+
+ class _DerivedType(XMLSchemaComponent):
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ # XXX remove attribute derivation, inconsistent
+ self.derivation = None
+ self.content = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ for i in contents:
+ component = SplitQName(i.getTagName())[1]
+ if component in self.__class__.contents['xsd']:
+ if component == 'annotation' and not self.annotation:
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(i)
+ continue
+ elif component == 'restriction' and not self.derivation:
+ self.derivation = self.__class__.Restriction(self)
+ elif component == 'extension' and not self.derivation:
+ self.derivation = self.__class__.Extension(self)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ self.derivation.fromDom(i)
+ self.content = self.derivation
+
+ class ComplexContent(_DerivedType,\
+ ComplexMarker):
+ """<complexContent>
+ parents:
+ complexType
+ attributes:
+ id -- ID
+ mixed -- boolean, false
+
+ contents:
+ annotation?, (restriction | extension)
+ """
+ attributes = {'id':None,
+ 'mixed':0}
+ contents = {'xsd':['annotation', 'restriction', 'extension']}
+ tag = 'complexContent'
+
+ def isMixed(self):
+ m = self.getAttribute('mixed')
+ if m == 0 or m == False:
+ return False
+ if isinstance(m, basestring) is True:
+ if m in ('false', '0'):
+ return False
+ if m in ('true', '1'):
+ return True
+ raise SchemaError, 'invalid value for attribute mixed(%s): %s'\
+ %(m, self.getItemTrace())
+
+ class _DerivationBase(XMLSchemaComponent):
+ """<extension>,<restriction>
+ parents:
+ complexContent
+ attributes:
+ id -- ID
+ base -- QName, required
+
+ contents:
+ annotation?, (group | all | choice | sequence)?,
+ (attribute | attributeGroup)*, anyAttribute?
+ """
+ required = ['base']
+ attributes = {'id':None,
+ 'base':None }
+ contents = {'xsd':['annotation', 'group', 'all', 'choice',\
+ 'sequence', 'attribute', 'attributeGroup', 'anyAttribute']}
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+ self.attr_content = None
+
+ def getAttributeContent(self):
+ return self.attr_content
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ indx = 0
+ num = len(contents)
+ #XXX ugly
+ if not num:
+ return
+ component = SplitQName(contents[indx].getTagName())[1]
+ if component == 'annotation':
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(contents[indx])
+ indx += 1
+ component = SplitQName(contents[indx].getTagName())[1]
+
+ if component == 'all':
+ self.content = All(self)
+ self.content.fromDom(contents[indx])
+ indx += 1
+ elif component == 'choice':
+ self.content = Choice(self)
+ self.content.fromDom(contents[indx])
+ indx += 1
+ elif component == 'sequence':
+ self.content = Sequence(self)
+ self.content.fromDom(contents[indx])
+ indx += 1
+ elif component == 'group':
+ self.content = ModelGroupReference(self)
+ self.content.fromDom(contents[indx])
+ indx += 1
+ else:
+ self.content = None
+
+ self.attr_content = []
+ while indx < num:
+ component = SplitQName(contents[indx].getTagName())[1]
+ if component == 'attribute':
+ if contents[indx].hasattr('ref'):
+ self.attr_content.append(AttributeReference(self))
+ else:
+ self.attr_content.append(LocalAttributeDeclaration(self))
+ elif component == 'attributeGroup':
+ if contents[indx].hasattr('ref'):
+ self.attr_content.append(AttributeGroupReference(self))
+ else:
+ self.attr_content.append(AttributeGroupDefinition(self))
+ elif component == 'anyAttribute':
+ self.attr_content.append(AttributeWildCard(self))
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(contents[indx].getTagName())
+ self.attr_content[-1].fromDom(contents[indx])
+ indx += 1
+
+ class Extension(_DerivationBase,
+ ExtensionMarker):
+ """<extension base>
+ parents:
+ complexContent
+ attributes:
+ id -- ID
+ base -- QName, required
+
+ contents:
+ annotation?, (group | all | choice | sequence)?,
+ (attribute | attributeGroup)*, anyAttribute?
+ """
+ tag = 'extension'
+
+ class Restriction(_DerivationBase,\
+ RestrictionMarker):
+ """<restriction base>
+ parents:
+ complexContent
+ attributes:
+ id -- ID
+ base -- QName, required
+
+ contents:
+ annotation?, (group | all | choice | sequence)?,
+ (attribute | attributeGroup)*, anyAttribute?
+ """
+ tag = 'restriction'
+
+
+ class SimpleContent(_DerivedType,\
+ SimpleMarker):
+ """<simpleContent>
+ parents:
+ complexType
+ attributes:
+ id -- ID
+
+ contents:
+ annotation?, (restriction | extension)
+ """
+ attributes = {'id':None}
+ contents = {'xsd':['annotation', 'restriction', 'extension']}
+ tag = 'simpleContent'
+
+ class Extension(XMLSchemaComponent,\
+ ExtensionMarker):
+ """<extension base>
+ parents:
+ simpleContent
+ attributes:
+ id -- ID
+ base -- QName, required
+
+ contents:
+ annotation?, (attribute | attributeGroup)*, anyAttribute?
+ """
+ required = ['base']
+ attributes = {'id':None,
+ 'base':None }
+ contents = {'xsd':['annotation', 'attribute', 'attributeGroup',
+ 'anyAttribute']}
+ tag = 'extension'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.attr_content = None
+
+ def getAttributeContent(self):
+ return self.attr_content
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ indx = 0
+ num = len(contents)
+
+ if num:
+ component = SplitQName(contents[indx].getTagName())[1]
+ if component == 'annotation':
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(contents[indx])
+ indx += 1
+ component = SplitQName(contents[indx].getTagName())[1]
+
+ content = []
+ while indx < num:
+ component = SplitQName(contents[indx].getTagName())[1]
+ if component == 'attribute':
+ if contents[indx].hasattr('ref'):
+ content.append(AttributeReference(self))
+ else:
+ content.append(LocalAttributeDeclaration(self))
+ elif component == 'attributeGroup':
+ content.append(AttributeGroupReference(self))
+ elif component == 'anyAttribute':
+ content.append(AttributeWildCard(self))
+ else:
+ raise SchemaError, 'Unknown component (%s)'\
+ %(contents[indx].getTagName())
+ content[-1].fromDom(contents[indx])
+ indx += 1
+ self.attr_content = tuple(content)
+
+
+ class Restriction(XMLSchemaComponent,\
+ RestrictionMarker):
+ """<restriction base>
+ parents:
+ simpleContent
+ attributes:
+ id -- ID
+ base -- QName, required
+
+ contents:
+ annotation?, simpleType?, (enumeration | length |
+ maxExclusive | maxInclusive | maxLength | minExclusive |
+ minInclusive | minLength | pattern | fractionDigits |
+ totalDigits | whiteSpace)*, (attribute | attributeGroup)*,
+ anyAttribute?
+ """
+ required = ['base']
+ attributes = {'id':None,
+ 'base':None }
+ contents = {'xsd':['annotation', 'simpleType', 'attribute',\
+ 'attributeGroup', 'anyAttribute'] + RestrictionMarker.facets}
+ tag = 'restriction'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+ self.attr_content = None
+
+ def getAttributeContent(self):
+ return self.attr_content
+
+ def fromDom(self, node):
+ self.content = []
+ self.setAttributes(node)
+ contents = self.getContents(node)
+
+ indx = 0
+ num = len(contents)
+ component = SplitQName(contents[indx].getTagName())[1]
+ if component == 'annotation':
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(contents[indx])
+ indx += 1
+ component = SplitQName(contents[indx].getTagName())[1]
+
+ content = []
+ while indx < num:
+ component = SplitQName(contents[indx].getTagName())[1]
+ if component == 'attribute':
+ if contents[indx].hasattr('ref'):
+ content.append(AttributeReference(self))
+ else:
+ content.append(LocalAttributeDeclaration(self))
+ elif component == 'attributeGroup':
+ content.append(AttributeGroupReference(self))
+ elif component == 'anyAttribute':
+ content.append(AttributeWildCard(self))
+ elif component == 'simpleType':
+ self.content.append(AnonymousSimpleType(self))
+ self.content[-1].fromDom(contents[indx])
+ else:
+ raise SchemaError, 'Unknown component (%s)'\
+ %(contents[indx].getTagName())
+ content[-1].fromDom(contents[indx])
+ indx += 1
+ self.attr_content = tuple(content)
+
+
+class LocalComplexType(ComplexType,\
+ LocalMarker):
+ """<complexType>
+ parents:
+ element
+ attributes:
+ id -- ID
+ mixed -- boolean, false
+
+ contents:
+ annotation?, (simpleContent | complexContent |
+ ((group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute?))
+ """
+ required = []
+ attributes = {'id':None,
+ 'mixed':0}
+ tag = 'complexType'
+
+
+class SimpleType(XMLSchemaComponent,\
+ DefinitionMarker,\
+ SimpleMarker):
+ """<simpleType name>
+ parents:
+ redefine, schema
+ attributes:
+ id -- ID
+ name -- NCName, required
+ final -- ('#all' | ('extension' | 'restriction' | 'list' | 'union')*),
+ schema.finalDefault
+
+ contents:
+ annotation?, (restriction | list | union)
+ """
+ required = ['name']
+ attributes = {'id':None,
+ 'name':None,
+ 'final':lambda self: self._parent().getFinalDefault()}
+ contents = {'xsd':['annotation', 'restriction', 'list', 'union']}
+ tag = 'simpleType'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+
+ def getElementDeclaration(self, attribute):
+ raise Warning, 'invalid operation for <%s>' %self.tag
+
+ def getTypeDefinition(self, attribute):
+ raise Warning, 'invalid operation for <%s>' %self.tag
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ for child in contents:
+ component = SplitQName(child.getTagName())[1]
+ if component == 'annotation':
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(child)
+ continue
+ break
+ else:
+ return
+ if component == 'restriction':
+ self.content = self.__class__.Restriction(self)
+ elif component == 'list':
+ self.content = self.__class__.List(self)
+ elif component == 'union':
+ self.content = self.__class__.Union(self)
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(component)
+ self.content.fromDom(child)
+
+ class Restriction(XMLSchemaComponent,\
+ RestrictionMarker):
+ """<restriction base>
+ parents:
+ simpleType
+ attributes:
+ id -- ID
+ base -- QName, required or simpleType child
+
+ contents:
+ annotation?, simpleType?, (enumeration | length |
+ maxExclusive | maxInclusive | maxLength | minExclusive |
+ minInclusive | minLength | pattern | fractionDigits |
+ totalDigits | whiteSpace)*
+ """
+ attributes = {'id':None,
+ 'base':None }
+ contents = {'xsd':['annotation', 'simpleType']+RestrictionMarker.facets}
+ tag = 'restriction'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+ self.facets = None
+
+ def getAttributeBase(self):
+ return XMLSchemaComponent.getAttribute(self, 'base')
+
+ def getTypeDefinition(self, attribute='base'):
+ return XMLSchemaComponent.getTypeDefinition(self, attribute)
+
+ def getSimpleTypeContent(self):
+ for el in self.content:
+ if el.isSimple(): return el
+ return None
+
+ def fromDom(self, node):
+ self.facets = []
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ content = []
+
+ for indx in range(len(contents)):
+ component = SplitQName(contents[indx].getTagName())[1]
+ if (component == 'annotation') and (not indx):
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(contents[indx])
+ continue
+ elif (component == 'simpleType') and (not indx or indx == 1):
+ content.append(AnonymousSimpleType(self))
+ content[-1].fromDom(contents[indx])
+ elif component in RestrictionMarker.facets:
+ self.facets.append(contents[indx])
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ self.content = tuple(content)
+
+
+ class Union(XMLSchemaComponent,
+ UnionMarker):
+ """<union>
+ parents:
+ simpleType
+ attributes:
+ id -- ID
+ memberTypes -- list of QNames, required or simpleType child.
+
+ contents:
+ annotation?, simpleType*
+ """
+ attributes = {'id':None,
+ 'memberTypes':None }
+ contents = {'xsd':['annotation', 'simpleType']}
+ tag = 'union'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+
+ def fromDom(self, node):
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ content = []
+
+ for indx in range(len(contents)):
+ component = SplitQName(contents[indx].getTagName())[1]
+ if (component == 'annotation') and (not indx):
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(contents[indx])
+ elif (component == 'simpleType'):
+ content.append(AnonymousSimpleType(self))
+ content[-1].fromDom(contents[indx])
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+ self.content = tuple(content)
+
+ class List(XMLSchemaComponent,
+ ListMarker):
+ """<list>
+ parents:
+ simpleType
+ attributes:
+ id -- ID
+ itemType -- QName, required or simpleType child.
+
+ contents:
+ annotation?, simpleType?
+ """
+ attributes = {'id':None,
+ 'itemType':None }
+ contents = {'xsd':['annotation', 'simpleType']}
+ tag = 'list'
+
+ def __init__(self, parent):
+ XMLSchemaComponent.__init__(self, parent)
+ self.annotation = None
+ self.content = None
+
+ def getItemType(self):
+ return self.attributes.get('itemType')
+
+ def getTypeDefinition(self, attribute='itemType'):
+ """
+ return the type refered to by itemType attribute or
+ the simpleType content. If returns None, then the
+ type refered to by itemType is primitive.
+ """
+ tp = XMLSchemaComponent.getTypeDefinition(self, attribute)
+ return tp or self.content
+
+ def fromDom(self, node):
+ self.annotation = None
+ self.content = None
+ self.setAttributes(node)
+ contents = self.getContents(node)
+ for indx in range(len(contents)):
+ component = SplitQName(contents[indx].getTagName())[1]
+ if (component == 'annotation') and (not indx):
+ self.annotation = Annotation(self)
+ self.annotation.fromDom(contents[indx])
+ elif (component == 'simpleType'):
+ self.content = AnonymousSimpleType(self)
+ self.content.fromDom(contents[indx])
+ break
+ else:
+ raise SchemaError, 'Unknown component (%s)' %(i.getTagName())
+
+
+class AnonymousSimpleType(SimpleType,\
+ SimpleMarker,\
+ LocalMarker):
+ """<simpleType>
+ parents:
+ attribute, element, list, restriction, union
+ attributes:
+ id -- ID
+
+ contents:
+ annotation?, (restriction | list | union)
+ """
+ required = []
+ attributes = {'id':None}
+ tag = 'simpleType'
+
+
+class Redefine:
+ """<redefine>
+ parents:
+ attributes:
+
+ contents:
+ """
+ tag = 'redefine'
+
+
+###########################
+###########################
+
+
+if sys.version_info[:2] >= (2, 2):
+ tupleClass = tuple
+else:
+ import UserTuple
+ tupleClass = UserTuple.UserTuple
+
+class TypeDescriptionComponent(tupleClass):
+ """Tuple of length 2, consisting of
+ a namespace and unprefixed name.
+ """
+ def __init__(self, args):
+ """args -- (namespace, name)
+ Remove the name's prefix, irrelevant.
+ """
+ if len(args) != 2:
+ raise TypeError, 'expecting tuple (namespace, name), got %s' %args
+ elif args[1].find(':') >= 0:
+ args = (args[0], SplitQName(args[1])[1])
+ tuple.__init__(self, args)
+ return
+
+ def getTargetNamespace(self):
+ return self[0]
+
+ def getName(self):
+ return self[1]
+
+
--- /dev/null
+"""Translate strings to and from SOAP 1.2 XML name encoding
+
+Implements rules for mapping application defined name to XML names
+specified by the w3 SOAP working group for SOAP version 1.2 in
+Appendix A of "SOAP Version 1.2 Part 2: Adjuncts", W3C Working Draft
+17, December 2001, <http://www.w3.org/TR/soap12-part2/#namemap>
+
+Also see <http://www.w3.org/2000/xp/Group/xmlp-issues>.
+
+Author: Gregory R. Warnes <Gregory.R.Warnes@Pfizer.com>
+Date:: 2002-04-25
+Version 0.9.0
+
+"""
+
+ident = "$Id$"
+
+from re import *
+
+
+def _NCNameChar(x):
+ return x.isalpha() or x.isdigit() or x=="." or x=='-' or x=="_"
+
+
+def _NCNameStartChar(x):
+ return x.isalpha() or x=="_"
+
+
+def _toUnicodeHex(x):
+ hexval = hex(ord(x[0]))[2:]
+ hexlen = len(hexval)
+ # Make hexval have either 4 or 8 digits by prepending 0's
+ if (hexlen==1): hexval = "000" + hexval
+ elif (hexlen==2): hexval = "00" + hexval
+ elif (hexlen==3): hexval = "0" + hexval
+ elif (hexlen==4): hexval = "" + hexval
+ elif (hexlen==5): hexval = "000" + hexval
+ elif (hexlen==6): hexval = "00" + hexval
+ elif (hexlen==7): hexval = "0" + hexval
+ elif (hexlen==8): hexval = "" + hexval
+ else: raise Exception, "Illegal Value returned from hex(ord(x))"
+
+ return "_x"+ hexval + "_"
+
+
+def _fromUnicodeHex(x):
+ return eval( r'u"\u'+x[2:-1]+'"' )
+
+
+def toXMLname(string):
+ """Convert string to a XML name."""
+ if string.find(':') != -1 :
+ (prefix, localname) = string.split(':',1)
+ else:
+ prefix = None
+ localname = string
+
+ T = unicode(localname)
+
+ N = len(localname)
+ X = [];
+ for i in range(N) :
+ if i< N-1 and T[i]==u'_' and T[i+1]==u'x':
+ X.append(u'_x005F_')
+ elif i==0 and N >= 3 and \
+ ( T[0]==u'x' or T[0]==u'X' ) and \
+ ( T[1]==u'm' or T[1]==u'M' ) and \
+ ( T[2]==u'l' or T[2]==u'L' ):
+ X.append(u'_xFFFF_' + T[0])
+ elif (not _NCNameChar(T[i])) or (i==0 and not _NCNameStartChar(T[i])):
+ X.append(_toUnicodeHex(T[i]))
+ else:
+ X.append(T[i])
+
+ if prefix:
+ return "%s:%s" % (prefix, u''.join(X))
+ return u''.join(X)
+
+
+def fromXMLname(string):
+ """Convert XML name to unicode string."""
+
+ retval = sub(r'_xFFFF_','', string )
+
+ def fun( matchobj ):
+ return _fromUnicodeHex( matchobj.group(0) )
+
+ retval = sub(r'_x[0-9A-Za-z]+_', fun, retval )
+
+ return retval
--- /dev/null
+#! /usr/bin/env python
+"""WSDL parsing services package for Web Services for Python."""
+
+ident = "$Id$"
+
+import WSDLTools
+import XMLname
+import logging
+
--- /dev/null
+#! /usr/bin/env python
+'''XML Canonicalization
+
+Patches Applied to xml.dom.ext.c14n:
+ http://sourceforge.net/projects/pyxml/
+
+ [ 1444526 ] c14n.py: http://www.w3.org/TR/xml-exc-c14n/ fix
+ -- includes [ 829905 ] c14n.py fix for bug #825115,
+ Date Submitted: 2003-10-24 23:43
+ -- include dependent namespace declarations declared in ancestor nodes
+ (checking attributes and tags),
+ -- handle InclusiveNamespaces PrefixList parameter
+
+This module generates canonical XML of a document or element.
+ http://www.w3.org/TR/2001/REC-xml-c14n-20010315
+and includes a prototype of exclusive canonicalization
+ http://www.w3.org/Signature/Drafts/xml-exc-c14n
+
+Requires PyXML 0.7.0 or later.
+
+Known issues if using Ft.Lib.pDomlette:
+ 1. Unicode
+ 2. does not white space normalize attributes of type NMTOKEN and ID?
+ 3. seems to be include "\n" after importing external entities?
+
+Note, this version processes a DOM tree, and consequently it processes
+namespace nodes as attributes, not from a node's namespace axis. This
+permits simple document and element canonicalization without
+XPath. When XPath is used, the XPath result node list is passed and used to
+determine if the node is in the XPath result list, but little else.
+
+Authors:
+ "Joseph M. Reagle Jr." <reagle@w3.org>
+ "Rich Salz" <rsalz@zolera.com>
+
+$Date$ by $Author$
+'''
+
+_copyright = '''Copyright 2001, Zolera Systems Inc. All Rights Reserved.
+Copyright 2001, MIT. All Rights Reserved.
+
+Distributed under the terms of:
+ Python 2.0 License or later.
+ http://www.python.org/2.0.1/license.html
+or
+ W3C Software License
+ http://www.w3.org/Consortium/Legal/copyright-software-19980720
+'''
+
+import string
+from xml.dom import Node
+try:
+ from xml.ns import XMLNS
+except:
+ class XMLNS:
+ BASE = "http://www.w3.org/2000/xmlns/"
+ XML = "http://www.w3.org/XML/1998/namespace"
+try:
+ import cStringIO
+ StringIO = cStringIO
+except ImportError:
+ import StringIO
+
+_attrs = lambda E: (E.attributes and E.attributes.values()) or []
+_children = lambda E: E.childNodes or []
+_IN_XML_NS = lambda n: n.name.startswith("xmlns")
+_inclusive = lambda n: n.unsuppressedPrefixes == None
+
+
+# Does a document/PI has lesser/greater document order than the
+# first element?
+_LesserElement, _Element, _GreaterElement = range(3)
+
+def _sorter(n1,n2):
+ '''_sorter(n1,n2) -> int
+ Sorting predicate for non-NS attributes.'''
+
+ i = cmp(n1.namespaceURI, n2.namespaceURI)
+ if i: return i
+ return cmp(n1.localName, n2.localName)
+
+
+def _sorter_ns(n1,n2):
+ '''_sorter_ns((n,v),(n,v)) -> int
+ "(an empty namespace URI is lexicographically least)."'''
+
+ if n1[0] == 'xmlns': return -1
+ if n2[0] == 'xmlns': return 1
+ return cmp(n1[0], n2[0])
+
+def _utilized(n, node, other_attrs, unsuppressedPrefixes):
+ '''_utilized(n, node, other_attrs, unsuppressedPrefixes) -> boolean
+ Return true if that nodespace is utilized within the node'''
+ if n.startswith('xmlns:'):
+ n = n[6:]
+ elif n.startswith('xmlns'):
+ n = n[5:]
+ if (n=="" and node.prefix in ["#default", None]) or \
+ n == node.prefix or n in unsuppressedPrefixes:
+ return 1
+ for attr in other_attrs:
+ if n == attr.prefix: return 1
+ # For exclusive need to look at attributes
+ if unsuppressedPrefixes is not None:
+ for attr in _attrs(node):
+ if n == attr.prefix: return 1
+
+ return 0
+
+
+def _inclusiveNamespacePrefixes(node, context, unsuppressedPrefixes):
+ '''http://www.w3.org/TR/xml-exc-c14n/
+ InclusiveNamespaces PrefixList parameter, which lists namespace prefixes that
+ are handled in the manner described by the Canonical XML Recommendation'''
+ inclusive = []
+ if node.prefix:
+ usedPrefixes = ['xmlns:%s' %node.prefix]
+ else:
+ usedPrefixes = ['xmlns']
+
+ for a in _attrs(node):
+ if a.nodeName.startswith('xmlns') or not a.prefix: continue
+ usedPrefixes.append('xmlns:%s' %a.prefix)
+
+ unused_namespace_dict = {}
+ for attr in context:
+ n = attr.nodeName
+ if n in unsuppressedPrefixes:
+ inclusive.append(attr)
+ elif n.startswith('xmlns:') and n[6:] in unsuppressedPrefixes:
+ inclusive.append(attr)
+ elif n.startswith('xmlns') and n[5:] in unsuppressedPrefixes:
+ inclusive.append(attr)
+ elif attr.nodeName in usedPrefixes:
+ inclusive.append(attr)
+ elif n.startswith('xmlns:'):
+ unused_namespace_dict[n] = attr.value
+
+ return inclusive, unused_namespace_dict
+
+#_in_subset = lambda subset, node: not subset or node in subset
+_in_subset = lambda subset, node: subset is None or node in subset # rich's tweak
+
+
+class _implementation:
+ '''Implementation class for C14N. This accompanies a node during it's
+ processing and includes the parameters and processing state.'''
+
+ # Handler for each node type; populated during module instantiation.
+ handlers = {}
+
+ def __init__(self, node, write, **kw):
+ '''Create and run the implementation.'''
+ self.write = write
+ self.subset = kw.get('subset')
+ self.comments = kw.get('comments', 0)
+ self.unsuppressedPrefixes = kw.get('unsuppressedPrefixes')
+ nsdict = kw.get('nsdict', { 'xml': XMLNS.XML, 'xmlns': XMLNS.BASE })
+
+ # Processing state.
+ self.state = (nsdict, {'xml':''}, {}, {}) #0422
+
+ if node.nodeType == Node.DOCUMENT_NODE:
+ self._do_document(node)
+ elif node.nodeType == Node.ELEMENT_NODE:
+ self.documentOrder = _Element # At document element
+ if not _inclusive(self):
+ inherited,unused = _inclusiveNamespacePrefixes(node, self._inherit_context(node),
+ self.unsuppressedPrefixes)
+ self._do_element(node, inherited, unused=unused)
+ else:
+ inherited = self._inherit_context(node)
+ self._do_element(node, inherited)
+ elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
+ pass
+ else:
+ raise TypeError, str(node)
+
+
+ def _inherit_context(self, node):
+ '''_inherit_context(self, node) -> list
+ Scan ancestors of attribute and namespace context. Used only
+ for single element node canonicalization, not for subset
+ canonicalization.'''
+
+ # Collect the initial list of xml:foo attributes.
+ xmlattrs = filter(_IN_XML_NS, _attrs(node))
+
+ # Walk up and get all xml:XXX attributes we inherit.
+ inherited, parent = [], node.parentNode
+ while parent and parent.nodeType == Node.ELEMENT_NODE:
+ for a in filter(_IN_XML_NS, _attrs(parent)):
+ n = a.localName
+ if n not in xmlattrs:
+ xmlattrs.append(n)
+ inherited.append(a)
+ parent = parent.parentNode
+ return inherited
+
+
+ def _do_document(self, node):
+ '''_do_document(self, node) -> None
+ Process a document node. documentOrder holds whether the document
+ element has been encountered such that PIs/comments can be written
+ as specified.'''
+
+ self.documentOrder = _LesserElement
+ for child in node.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ self.documentOrder = _Element # At document element
+ self._do_element(child)
+ self.documentOrder = _GreaterElement # After document element
+ elif child.nodeType == Node.PROCESSING_INSTRUCTION_NODE:
+ self._do_pi(child)
+ elif child.nodeType == Node.COMMENT_NODE:
+ self._do_comment(child)
+ elif child.nodeType == Node.DOCUMENT_TYPE_NODE:
+ pass
+ else:
+ raise TypeError, str(child)
+ handlers[Node.DOCUMENT_NODE] = _do_document
+
+
+ def _do_text(self, node):
+ '''_do_text(self, node) -> None
+ Process a text or CDATA node. Render various special characters
+ as their C14N entity representations.'''
+ if not _in_subset(self.subset, node): return
+ s = string.replace(node.data, "&", "&")
+ s = string.replace(s, "<", "<")
+ s = string.replace(s, ">", ">")
+ s = string.replace(s, "\015", "
")
+ if s: self.write(s)
+ handlers[Node.TEXT_NODE] = _do_text
+ handlers[Node.CDATA_SECTION_NODE] = _do_text
+
+
+ def _do_pi(self, node):
+ '''_do_pi(self, node) -> None
+ Process a PI node. Render a leading or trailing #xA if the
+ document order of the PI is greater or lesser (respectively)
+ than the document element.
+ '''
+ if not _in_subset(self.subset, node): return
+ W = self.write
+ if self.documentOrder == _GreaterElement: W('\n')
+ W('<?')
+ W(node.nodeName)
+ s = node.data
+ if s:
+ W(' ')
+ W(s)
+ W('?>')
+ if self.documentOrder == _LesserElement: W('\n')
+ handlers[Node.PROCESSING_INSTRUCTION_NODE] = _do_pi
+
+
+ def _do_comment(self, node):
+ '''_do_comment(self, node) -> None
+ Process a comment node. Render a leading or trailing #xA if the
+ document order of the comment is greater or lesser (respectively)
+ than the document element.
+ '''
+ if not _in_subset(self.subset, node): return
+ if self.comments:
+ W = self.write
+ if self.documentOrder == _GreaterElement: W('\n')
+ W('<!--')
+ W(node.data)
+ W('-->')
+ if self.documentOrder == _LesserElement: W('\n')
+ handlers[Node.COMMENT_NODE] = _do_comment
+
+
+ def _do_attr(self, n, value):
+ ''''_do_attr(self, node) -> None
+ Process an attribute.'''
+
+ W = self.write
+ W(' ')
+ W(n)
+ W('="')
+ s = string.replace(value, "&", "&")
+ s = string.replace(s, "<", "<")
+ s = string.replace(s, '"', '"')
+ s = string.replace(s, '\011', '	')
+ s = string.replace(s, '\012', '
')
+ s = string.replace(s, '\015', '
')
+ W(s)
+ W('"')
+
+
+ def _do_element(self, node, initial_other_attrs = [], unused = None):
+ '''_do_element(self, node, initial_other_attrs = [], unused = {}) -> None
+ Process an element (and its children).'''
+
+ # Get state (from the stack) make local copies.
+ # ns_parent -- NS declarations in parent
+ # ns_rendered -- NS nodes rendered by ancestors
+ # ns_local -- NS declarations relevant to this element
+ # xml_attrs -- Attributes in XML namespace from parent
+ # xml_attrs_local -- Local attributes in XML namespace.
+ # ns_unused_inherited -- not rendered namespaces, used for exclusive
+ ns_parent, ns_rendered, xml_attrs = \
+ self.state[0], self.state[1].copy(), self.state[2].copy() #0422
+
+ ns_unused_inherited = unused
+ if unused is None:
+ ns_unused_inherited = self.state[3].copy()
+
+ ns_local = ns_parent.copy()
+ inclusive = _inclusive(self)
+ xml_attrs_local = {}
+
+ # Divide attributes into NS, XML, and others.
+ other_attrs = []
+ in_subset = _in_subset(self.subset, node)
+ for a in initial_other_attrs + _attrs(node):
+ if a.namespaceURI == XMLNS.BASE:
+ n = a.nodeName
+ if n == "xmlns:": n = "xmlns" # DOM bug workaround
+ ns_local[n] = a.nodeValue
+ elif a.namespaceURI == XMLNS.XML:
+ if inclusive or (in_subset and _in_subset(self.subset, a)): #020925 Test to see if attribute node in subset
+ xml_attrs_local[a.nodeName] = a #0426
+ else:
+ if _in_subset(self.subset, a): #020925 Test to see if attribute node in subset
+ other_attrs.append(a)
+
+# # TODO: exclusive, might need to define xmlns:prefix here
+# if not inclusive and a.prefix is not None and not ns_rendered.has_key('xmlns:%s' %a.prefix):
+# ns_local['xmlns:%s' %a.prefix] = ??
+
+ #add local xml:foo attributes to ancestor's xml:foo attributes
+ xml_attrs.update(xml_attrs_local)
+
+ # Render the node
+ W, name = self.write, None
+ if in_subset:
+ name = node.nodeName
+ if not inclusive:
+ if node.prefix is not None:
+ prefix = 'xmlns:%s' %node.prefix
+ else:
+ prefix = 'xmlns'
+
+ if not ns_rendered.has_key(prefix) and not ns_local.has_key(prefix):
+ if not ns_unused_inherited.has_key(prefix):
+ raise RuntimeError,\
+ 'For exclusive c14n, unable to map prefix "%s" in %s' %(
+ prefix, node)
+
+ ns_local[prefix] = ns_unused_inherited[prefix]
+ del ns_unused_inherited[prefix]
+
+ W('<')
+ W(name)
+
+ # Create list of NS attributes to render.
+ ns_to_render = []
+ for n,v in ns_local.items():
+
+ # If default namespace is XMLNS.BASE or empty,
+ # and if an ancestor was the same
+ if n == "xmlns" and v in [ XMLNS.BASE, '' ] \
+ and ns_rendered.get('xmlns') in [ XMLNS.BASE, '', None ]:
+ continue
+
+ # "omit namespace node with local name xml, which defines
+ # the xml prefix, if its string value is
+ # http://www.w3.org/XML/1998/namespace."
+ if n in ["xmlns:xml", "xml"] \
+ and v in [ 'http://www.w3.org/XML/1998/namespace' ]:
+ continue
+
+
+ # If not previously rendered
+ # and it's inclusive or utilized
+ if (n,v) not in ns_rendered.items():
+ if inclusive or _utilized(n, node, other_attrs, self.unsuppressedPrefixes):
+ ns_to_render.append((n, v))
+ elif not inclusive:
+ ns_unused_inherited[n] = v
+
+ # Sort and render the ns, marking what was rendered.
+ ns_to_render.sort(_sorter_ns)
+ for n,v in ns_to_render:
+ self._do_attr(n, v)
+ ns_rendered[n]=v #0417
+
+ # If exclusive or the parent is in the subset, add the local xml attributes
+ # Else, add all local and ancestor xml attributes
+ # Sort and render the attributes.
+ if not inclusive or _in_subset(self.subset,node.parentNode): #0426
+ other_attrs.extend(xml_attrs_local.values())
+ else:
+ other_attrs.extend(xml_attrs.values())
+ other_attrs.sort(_sorter)
+ for a in other_attrs:
+ self._do_attr(a.nodeName, a.value)
+ W('>')
+
+ # Push state, recurse, pop state.
+ state, self.state = self.state, (ns_local, ns_rendered, xml_attrs, ns_unused_inherited)
+ for c in _children(node):
+ _implementation.handlers[c.nodeType](self, c)
+ self.state = state
+
+ if name: W('</%s>' % name)
+ handlers[Node.ELEMENT_NODE] = _do_element
+
+
+def Canonicalize(node, output=None, **kw):
+ '''Canonicalize(node, output=None, **kw) -> UTF-8
+
+ Canonicalize a DOM document/element node and all descendents.
+ Return the text; if output is specified then output.write will
+ be called to output the text and None will be returned
+ Keyword parameters:
+ nsdict: a dictionary of prefix:uri namespace entries
+ assumed to exist in the surrounding context
+ comments: keep comments if non-zero (default is 0)
+ subset: Canonical XML subsetting resulting from XPath
+ (default is [])
+ unsuppressedPrefixes: do exclusive C14N, and this specifies the
+ prefixes that should be inherited.
+ '''
+ if output:
+ apply(_implementation, (node, output.write), kw)
+ else:
+ s = StringIO.StringIO()
+ apply(_implementation, (node, s.write), kw)
+ return s.getvalue()
--- /dev/null
+# Copyright (c) 2003, The Regents of the University of California,
+# through Lawrence Berkeley National Laboratory (subject to receipt of
+# any required approvals from the U.S. Dept. of Energy). All rights
+# reserved.
+#
+"""Logging"""
+ident = "$Id$"
+import os, sys
+
+WARN = 1
+DEBUG = 2
+
+
+class ILogger:
+ '''Logger interface, by default this class
+ will be used and logging calls are no-ops.
+ '''
+ level = 0
+ def __init__(self, msg):
+ return
+ def warning(self, *args, **kw):
+ return
+ def debug(self, *args, **kw):
+ return
+ def error(self, *args, **kw):
+ return
+ def setLevel(cls, level):
+ cls.level = level
+ setLevel = classmethod(setLevel)
+
+ debugOn = lambda self: self.level >= DEBUG
+ warnOn = lambda self: self.level >= WARN
+
+
+class BasicLogger(ILogger):
+ last = ''
+
+ def __init__(self, msg, out=sys.stdout):
+ self.msg, self.out = msg, out
+
+ def warning(self, msg, *args, **kw):
+ if self.warnOn() is False: return
+ if BasicLogger.last != self.msg:
+ BasicLogger.last = self.msg
+ print >>self, "---- ", self.msg, " ----"
+ print >>self, " %s " %self.WARN,
+ print >>self, msg %args
+ WARN = '[WARN]'
+ def debug(self, msg, *args, **kw):
+ if self.debugOn() is False: return
+ if BasicLogger.last != self.msg:
+ BasicLogger.last = self.msg
+ print >>self, "---- ", self.msg, " ----"
+ print >>self, " %s " %self.DEBUG,
+ print >>self, msg %args
+ DEBUG = '[DEBUG]'
+ def error(self, msg, *args, **kw):
+ if BasicLogger.last != self.msg:
+ BasicLogger.last = self.msg
+ print >>self, "---- ", self.msg, " ----"
+ print >>self, " %s " %self.ERROR,
+ print >>self, msg %args
+ ERROR = '[ERROR]'
+
+ def write(self, *args):
+ '''Write convenience function; writes strings.
+ '''
+ for s in args: self.out.write(s)
+ event = ''.join(*args)
+
+
+_LoggerClass = BasicLogger
+
+class GridLogger(ILogger):
+ def debug(self, msg, *args, **kw):
+ kw['component'] = self.msg
+ gridLog(event=msg %args, level='DEBUG', **kw)
+
+ def warning(self, msg, *args, **kw):
+ kw['component'] = self.msg
+ gridLog(event=msg %args, level='WARNING', **kw)
+
+ def error(self, msg, *args, **kw):
+ kw['component'] = self.msg
+ gridLog(event=msg %args, level='ERROR', **kw)
+
+
+#
+# Registry of send functions for gridLog
+#
+GLRegistry = {}
+
+class GLRecord(dict):
+ """Grid Logging Best Practices Record, Distributed Logging Utilities
+
+ The following names are reserved:
+
+ event -- log event name
+ Below is EBNF for the event name part of a log message.
+ name = <nodot> ( "." <name> )?
+ nodot = {RFC3896-chars except "."}
+
+ Suffixes:
+ start: Immediately before the first action in a task.
+ end: Immediately after the last action in a task (that succeeded).
+ error: an error condition that does not correspond to an end event.
+
+ ts -- timestamp
+ level -- logging level (see levels below)
+ status -- integer status code
+ gid -- global grid identifier
+ gid, cgid -- parent/child identifiers
+ prog -- program name
+
+
+ More info: http://www.cedps.net/wiki/index.php/LoggingBestPractices#Python
+
+ reserved -- list of reserved names,
+ omitname -- list of reserved names, output only values ('ts', 'event',)
+ levels -- dict of levels and description
+ """
+ reserved = ('ts', 'event', 'level', 'status', 'gid', 'prog')
+ omitname = ()
+ levels = dict(FATAL='Component cannot continue, or system is unusable.',
+ ALERT='Action must be taken immediately.',
+ CRITICAL='Critical conditions (on the system).',
+ ERROR='Errors in the component; not errors from elsewhere.',
+ WARNING='Problems that are recovered from, usually.',
+ NOTICE='Normal but significant condition.',
+ INFO='Informational messages that would be useful to a deployer or administrator.',
+ DEBUG='Lower level information concerning program logic decisions, internal state, etc.',
+ TRACE='Finest granularity, similar to "stepping through" the component or system.',
+ )
+
+ def __init__(self, date=None, **kw):
+ kw['ts'] = date or self.GLDate()
+ kw['gid'] = kw.get('gid') or os.getpid()
+ dict.__init__(self, kw)
+
+ def __str__(self):
+ """
+ """
+ from cStringIO import StringIO
+ s = StringIO(); n = " "
+ reserved = self.reserved; omitname = self.omitname; levels = self.levels
+
+ for k in ( list(filter(lambda i: self.has_key(i), reserved)) +
+ list(filter(lambda i: i not in reserved, self.keys()))
+ ):
+ v = self[k]
+ if k in omitname:
+ s.write( "%s " %self.format[type(v)](v) )
+ continue
+
+ if k == reserved[2] and v not in levels:
+ pass
+
+ s.write( "%s=%s " %(k, self.format[type(v)](v) ) )
+
+ s.write("\n")
+ return s.getvalue()
+
+ class GLDate(str):
+ """Grid logging Date Format
+ all timestamps should all be in the same time zone (UTC).
+ Grid timestamp value format that is a highly readable variant of the ISO8601 time standard [1]:
+
+ YYYY-MM-DDTHH:MM:SS.SSSSSSZ
+
+ """
+ def __new__(self, args=None):
+ """args -- datetime (year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
+ """
+ import datetime
+ args = args or datetime.datetime.utcnow()
+ l = (args.year, args.month, args.day, args.hour, args.minute, args.second,
+ args.microsecond, args.tzinfo or 'Z')
+
+ return str.__new__(self, "%04d-%02d-%02dT%02d:%02d:%02d.%06d%s" %l)
+
+ format = { int:str, float:lambda x: "%lf" % x, long:str, str:lambda x:x,
+ unicode:str, GLDate:str, }
+
+
+def gridLog(**kw):
+ """Send GLRecord, Distributed Logging Utilities
+ If the scheme is passed as a keyword parameter
+ the value is expected to be a callable function
+ that takes 2 parameters: url, outputStr
+
+ GRIDLOG_ON -- turn grid logging on
+ GRIDLOG_DEST -- provide URL destination
+ """
+ import os
+
+ if not bool( int(os.environ.get('GRIDLOG_ON', 0)) ):
+ return
+
+ url = os.environ.get('GRIDLOG_DEST')
+ if url is None:
+ return
+
+ ## NOTE: urlparse problem w/customized schemes
+ try:
+ scheme = url[:url.find('://')]
+ send = GLRegistry[scheme]
+ send( url, str(GLRecord(**kw)), )
+ except Exception, ex:
+ print >>sys.stderr, "*** gridLog failed -- %s" %(str(kw))
+
+
+def sendUDP(url, outputStr):
+ from socket import socket, AF_INET, SOCK_DGRAM
+ idx1 = url.find('://') + 3; idx2 = url.find('/', idx1)
+ if idx2 < idx1: idx2 = len(url)
+ netloc = url[idx1:idx2]
+ host,port = (netloc.split(':')+[80])[0:2]
+ socket(AF_INET, SOCK_DGRAM).sendto( outputStr, (host,int(port)), )
+
+def writeToFile(url, outputStr):
+ print >> open(url.split('://')[1], 'a+'), outputStr
+
+GLRegistry["gridlog-udp"] = sendUDP
+GLRegistry["file"] = writeToFile
+
+
+def setBasicLogger():
+ '''Use Basic Logger.
+ '''
+ setLoggerClass(BasicLogger)
+ BasicLogger.setLevel(0)
+
+def setGridLogger():
+ '''Use GridLogger for all logging events.
+ '''
+ setLoggerClass(GridLogger)
+
+def setBasicLoggerWARN():
+ '''Use Basic Logger.
+ '''
+ setLoggerClass(BasicLogger)
+ BasicLogger.setLevel(WARN)
+
+def setBasicLoggerDEBUG():
+ '''Use Basic Logger.
+ '''
+ setLoggerClass(BasicLogger)
+ BasicLogger.setLevel(DEBUG)
+
+def setLoggerClass(loggingClass):
+ '''Set Logging Class.
+ '''
+
+def setLoggerClass(loggingClass):
+ '''Set Logging Class.
+ '''
+ assert issubclass(loggingClass, ILogger), 'loggingClass must subclass ILogger'
+ global _LoggerClass
+ _LoggerClass = loggingClass
+
+def setLevel(level=0):
+ '''Set Global Logging Level.
+ '''
+ ILogger.level = level
+
+def getLevel():
+ return ILogger.level
+
+def getLogger(msg):
+ '''Return instance of Logging class.
+ '''
+ return _LoggerClass(msg)
+
+
--- /dev/null
+Two top level modules have been provided to run the tests. "test_wstools.py"
+is used to run all of the local tests. "test_wstools_net.py" is used to run
+all of the tests that require network access.
+
+Add the -v option for more informative feedback.
+
+ADDING TESTS:
+ 1. For Stand-Alone tests add WSDL FILE to appropriate archive file
+ Need to add a NEW Archive?:
+ config.txt [files] "archive" -- tuple of all archive files,
+ if you need to create a new archive append the archive
+ name to the 'archive' tuple.
+
+ 2. Edit config.txt section(s):
+ option -- name by which service will be referenced in test case.
+ Need an entry under appropriate section(s), this name
+ must be unique within each section it appears but it may
+ appear in multiple sections.
+
+ config.txt "test" sections:
+ Stand-Alone -- add "option" under [services_by_file]
+ eg. amazon = exports/AmazonWebServices.wsdl
+
+ Network -- add "option" under [services_by_http]
+ eg. amazon = http://soap.amazon.com/schemas/AmazonWebServices.wsdl
+
+ Broken -- add "option" under [broken]
+
+ 3. Done
+
+
+CONTENTS OF SAMPLE WSDL/XSD:
+ schema -- Taken from globus-3.0.1(http://www.globus.org)
+ xmethods -- Taken from XMethods(http://www.xmethods.com)
+ airport.wsdl
+ AmazonWebServices.wsdl
+ books.wsdl
+ Distance.wsdl
+ freedb.wsdl
+ globalweather.wsdl
+ IHaddock.wsdl
+ ip2geo.wsdl
+ magic.wsdl
+ query.wsdl
+ RateInfo.wsdl
+ SHA1Encrypt.wsdl
+ siteInspect.wsdl
+ TemperatureService.wsdl
+ usweather.wsdl
+ rtf2html.xml
+ SolveSystem.wsdl.xml
+ zip2geo.wsdl
--- /dev/null
+#! /usr/bin/env python
--- /dev/null
+############################################################################
+# Joshua R. Boverhof, David W. Robertson, LBNL
+# See Copyright for copyright notice!
+###########################################################################
+
+###########################################################################
+# Config file for the unit test framework.
+# Sections below.
+###########################################################################
+
+
+
+##########################################################################
+# SECTION [files] - archives of wsdl/xsd files.
+#
+##########################################################################
+[files]
+archives = ('xmethods.tar.gz', 'schema.tar.gz')
+
+##########################################################################
+# SECTION [services_by_file] - all services locally available for
+# testing.
+##########################################################################
+[services_by_file]
+ogsi = schema/ogsi/ogsi_service.wsdl
+airport = xmethods/airport.wsdl
+distance = xmethods/Distance.wsdl
+freedb = xmethods/freedb.wsdl
+globalweather = xmethods/globalweather.wsdl
+IHaddock = xmethods/IHaddock.wsdl
+ip2geo = xmethods/ip2geo.wsdl
+magic = xmethods/magic.wsdl
+query = xmethods/query.wsdl
+RateInfo = xmethods/RateInfo.wsdl
+SHA1Encrypt = xmethods/SHA1Encrypt.wsdl
+siteInsepct = xmethods/siteInspect.wsdl
+TemperatureService = xmethods/TemperatureService.wsdl
+usweather = xmethods/usweather.wsdl
+zip2geo = xmethods/zip2geo.wsdl
+SolveSystem = xmethods/SolveSystem.wsdl.xml
+
+##########################################################################
+# SECTION [services_by_http] -
+##########################################################################
+[services_by_http]
+
+# no schemas
+AbysalSendEmail = http://www.abysal.com/soap/AbysalEmail.wsdl
+BNQuoteService = http://www.xmethods.net/sd/2001/BNQuoteService.wsdl
+BabelFishService = http://www.xmethods.net/sd/2001/BabelFishService.wsdl
+Bible = http://www.stgregorioschurchdc.org/wsdl/Bible.wsdl
+Blast = http://xml.nig.ac.jp/wsdl/Blast.wsdl
+CATrafficService = http://www.xmethods.net/sd/2001/CATrafficService.wsdl
+Calendar = http://www.stgregorioschurchdc.org/wsdl/Calendar.wsdl
+ClustalW = http://xml.nig.ac.jp/wsdl/ClustalW.wsdl
+CountryInfoLookupService = http://www.cs.uga.edu/~sent/xmethods/CountryInfoLookup.wsdl
+CurrencyExchangeService = http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl
+DDBJ = http://xml.nig.ac.jp/wsdl/DDBJ.wsdl
+DiscordianService = http://www.compkarori.com/wsdl/discordian.wsdl
+DistanceService = http://webservices.imacination.com/distance/Distance.jws?wsdl
+DocServService = http://docserv.aurigalogic.com/docserv.wsdl
+EMWebFunctionWS = http://www.eyemaginations.com/cgi-bin/getWSDL.pl?wsdl=WebFunction.wsdl
+Fasta = http://xml.nig.ac.jp/wsdl/Fasta.wsdl
+FaxService = http://oneoutbox.com/wsdl/FaxService.wsdl
+FreeFaxService = http://www.OneOutBox.com/wsdl/FreeFaxService.wsdl
+GetEntry = http://xml.nig.ac.jp/wsdl/GetEntry.wsdl
+IBorlandBabelservice = http://ww6.borland.com/webservices/BorlandBabel/BorlandBabel.exe/wsdl/IBorlandBabel
+IBorlandChessservice = http://www.danmarinescu.com/WebServices/ChessCGIServer.exe/wsdl/IBorlandChess
+IDutchservice = http://www.ebob42.com/cgi-bin/NumberToWordsInDutch.exe/wsdl/IDutch
+IEmailServiceservice = http://webservices.matlus.com/scripts/emailwebservice.dll/wsdl/IEmailService
+IHeadLineservice = http://www.ebob42.com/cgi-bin/DrBobsClinic.exe/wsdl/IHeadline
+IMapQuestservice = http://ww6.borland.com/webservices/MapQuest/MapQuest.exe/wsdl/IMapQuest
+IMsSessionBrokerServiceservice = http://webservices.matlus.com/scripts/sessionservice.dll/wsdl/IMsSessionBrokerService
+IODCODESPOSTAUXservice = http://www.e-naxos.com/scripts/enwscp.dll/wsdl/IODCODESPOSTAUX
+IPGPKeyServerservice = http://www.marotz.se/PGPKeyServer/PGPKeyServiceX.exe/wsdl/IPGPKeyServer
+IPrimeGeneratorservice = http://www.jusufdarmawan.com/wsprimegenerator.exe/wsdl/IPrimeGenerator
+IRomanservice = http://www.ebob42.com/cgi-bin/Romulan.exe/wsdl/IRoman
+ISMSServiceservice = http://sms.idws.com/soap/smsservice.dll/wsdl/ISMSService
+ISlashdotHeadlineProviderservice = http://www.marotz.se/scripts/SlashdotHeadlines.exe/wsdl/ISlashdotHeadlineProvider
+ISwedishZipInfoservice = http://www.marotz.se/scripts/zipinfo.exe/wsdl/ISwedishZipInfo
+ITempConverterservice = http://developerdays.com/cgi-bin/tempconverter.exe/wsdl/ITempConverter
+IWSMazeServerservice = http://www.culand.net/WebServices/bin/WSMaze_Server.dll/wsdl/IWSMazeServer
+IWagAddressServerSingleservice = http://62.212.78.36/cgi-bin/WagAddressServerSingle.exe/wsdl/IWagAddressServerSingle
+IWhoIsservice = http://webservices.matlus.com/scripts/whoiswebservice.dll/wsdl/IWhoIs
+Ieconomicservice = http://www.suiyi.com/soap/economic.dll/wsdl/Ieconomic
+IgetNumbersservice = http://reto.checkit.ch/Scripts/Lotto.dll/wsdl/IgetNumbers
+Iws_Verify_NRICservice = http://www.rightsecurity.biz/NRICWebServices/NRICWebServices.dll/wsdl/Iws_Verify_NRIC
+KRSS_DAML_Service = http://digilander.libero.it/mamo78/KRSS_DAML_Service.wsdl
+MBWSSoapService = http://www.extensio.com:8080/ExtensioInfoServer/mbsoap/MBWSSoapServices.wsdl
+SRS = http://xml.nig.ac.jp/wsdl/SRS.wsdl
+ServiceSMS = http://smsserver.dotnetisp.com/servicesms.asmx?WSDL
+TemperatureService = http://www.xmethods.net/sd/2001/TemperatureService.wsdl
+TxSearch = http://xml.nig.ac.jp/wsdl/TxSearch.wsdl
+UrduSOAP = http://www.apniurdu.com/SOAP/Urdu2.wsdl
+WSFindMP3 = http://xmlrad.com/WSFindMP3Bin/WSFindMP3.dll/WSDL
+WSGenerator = http://xmlrad.com/WSGeneratorBin/WSGenerator.dll/WSDL
+WorldTimeService = http://ws.digiposs.com/WorldTime.jws?wsdl
+XEMBL = http://www.ebi.ac.uk/xembl/XEMBL.wsdl
+XMethodsFilesystemService = http://www.xmethods.net/sd/2001/XMethodsFilesystemService.wsdl
+YIM Service = http://www.scdi.org/~avernet/webservice/yim.wsdl
+YahooUserPingService = http://www.allesta.net:51110/webservices/wsdl/YahooUserPingService.xml
+convert = http://www.cosme.nu/services/convert.php?wsdl
+dns = http://www.cosme.nu/services/dns.php?wsdl
+eBayWatcherService = http://www.xmethods.net/sd/2001/EBayWatcherService.wsdl
+finnwords = http://www.nickhodge.com/nhodge/finnwords/finnwords.wsdl
+pop = http://www.cosme.nu/services/pop.php?wsdl
+
+
+#simple types
+
+ABA = http://www.webservicex.net/aba.asmx?WSDL
+AmazonBox = http://www.xmlme.com/WSAmazonBox.asmx?WSDL
+AustralianPostCode = http://www.webservicex.net/AustralianPostCode.asmx?WSDL
+Autoloan = http://upload.eraserver.net/circle24/autoloan.asmx?wsdl
+BNPrice = http://www.abundanttech.com/webservices/bnprice/bnprice.wsdl
+BankCode = http://appserver.pepperzak.net/bankcode/BankCodeEJBHome/wsdl.jsp
+BarCode = http://www.webservicex.net/barcode.asmx?WSDL
+BibleWebservice = http://www.webservicex.net/BibleWebservice.asmx?wsdl
+Braille = http://www.webservicex.net/braille.asmx?WSDL
+CEqImage = http://www.quisque.com/fr/techno/eqimage/eqimage.asmx?WSDL
+CFRSearch = http://www.oakleaf.ws/cfrsearchws/cfrsearchws.asmx?wsdl
+CFRSect = http://www.oakleaf.ws/cfrsectws/cfrsectws.asmx?wsdl
+CFRToc = http://www.oakleaf.ws/cfrtocws/cfrtocws.asmx?wsdl
+CodeGenerator = http://www.esynaps.com/webservices/codegenerator.asmx?WSDL
+CreditCardValidator = http://www.richsolutions.com/RichPayments/RichCardValidator.asmx?WSDL
+CurrencyConvertor = http://www.webservicex.net/CurrencyConvertor.asmx?wsdl
+Currencyws = http://glkev.webs.innerhost.com/glkev_ws/Currencyws.asmx?WSDL
+DailyDilbert = http://www.esynaps.com/WebServices/DailyDiblert.asmx?WSDL
+DotnetDailyFact = http://www.xmlme.com/WSDailyNet.asmx?WSDL
+EMBLNucleotideSequenceWebService = http://www.webservicex.net/EMBLNucleotideSequenceWebService.asmx?wsdl
+ElectronicProductsFinder = http://www.xmlme.com/WSElectronics.asmx?WSDL
+EncryptionWS = http://test.mapfrepr.net/Encryption/Encryption.asmx?WSDL
+Fax = http://ws.acrosscommunications.com/Fax.asmx?WSDL
+FinanceService = http://www.webservicex.net/FinanceService.asmx?WSDL
+Fortune = http://adrianr.dyndns.org/Fortune/Fortune.wsdl
+GetCustomNews = http://www.xmlme.com/WSCustNews.asmx?WSDL
+GetLocalTime = http://services.develop.co.za/GetLocalTime.asmx?WSDL
+GlobalWeather = http://www.webservicex.net/globalweather.asmx?WSDL
+HCPCS = http://www.webservicex.net/hcpcs.asmx?WSDL
+IBANFunctions = http://www.bitounis.com/IBAN/IBANFuncs.asmx?WSDL
+ICD10 = http://www.webservicex.net/icd10.asmx?WSDL
+ICD9 = http://www.webservicex.net/icd9.asmx?WSDL
+ICD9Drug = http://www.webservicex.net/icd9drug.asmx?WSDL
+ICD9ToICD10 = http://www.webservicex.net/icd9toicd10.asmx?WSDL
+ICQ = http://ws.acrosscommunications.com/ICQ.asmx?WSDL
+ISearchSwedishPersonservice = http://www.marotz.se/scripts/searchperson.exe/wsdl/ISearchSwedishPerson
+InstantMessageAlert = http://www.bindingpoint.com/ws/imalert/imalert.asmx?wsdl
+LocalTime = http://www.ripedev.com/webservices/LocalTime.asmx?WSDL
+MSProxy = http://www.esynaps.com/WebServices/MsProxy.asmx?WSDL
+MXChecker = http://beta2.eraserver.net/webservices/mxchecker/mxchecker.asmx?WSDL
+NAICS = http://www.webservicex.net/NAICS.asmx?wsdl
+NFLNews = http://www.esynaps.com/WebServices/NFLNews.asmx?WSDL
+NumPager = http://ws.acrosscommunications.com/NumPager.asmx?WSDL
+OTNNews = http://otn.oracle.com/ws/otnnews?WSDL
+Paracite = http://paracite.ecs.soton.ac.uk/paracite.wsdl
+Phone = http://ws.acrosscommunications.com/Phone.asmx?WSDL
+Puki = http://www.barnaland.is/dev/puki.asmx?WSDL
+QueryIP = http://ws.cdyne.com/whoisforip/queryip.asmx?wsdl
+Quotes = http://www.seshakiran.com/QuoteService/QuotesService.asmx?wsdl
+QuranVerse = http://aspnet.lamaan.com/webservices/QuranVerse.asmx?WSDL
+RSAFuncs = http://www.bitounis.com/RSAFunctions/RSAFuncs.asmx?WSDL
+RSStoHTML = http://www.webservicex.net/RssToHTML.asmx?WSDL
+#SMS = http://ws.acrosscommunications.com/SMS.asmx?WSDL
+#SMS_1 = http://www.barnaland.is/dev/sms.asmx?WSDL
+SQLDataSoap = http://www.SoapClient.com/xml/SQLDataSoap.wsdl
+SecureXML = http://www.securexml.net/securexml/securexml.wsdl
+SendSMSWorld = http://www.webservicex.net/sendsmsworld.asmx?WSDL
+Shakespeare = http://www.xmlme.com/WSShakespeare.asmx?WSDL
+SportingGoodsFinder = http://www.xmlme.com/WSSportingGoods.asmx?WSDL
+StockQuote = http://www.webservicex.net/stockquote.asmx?WSDL
+StockQuotes = http://www.gama-system.com/webservices/stockquotes.asmx?wsdl
+TAP = http://ws.acrosscommunications.com/TAP.asmx?WSDL
+UDDIBusinessFinder = http://www.webservicex.net/UDDIBusinessFinder.asmx?WSDL
+UKLocation = http://www.webservicex.net/uklocation.asmx?WSDL
+UNSPSCConvert = http://www.codemechanisms.co.uk/WebServices/UNSPSC.asmx?WSDL
+USWeather = http://www.webservicex.net/usweather.asmx?WSDL
+ValidateEmail = http://www.webservicex.net/ValidateEmail.asmx?WSDL
+VideoGamesFinder = http://www.xmlme.com/WSVideoGames.asmx?WSDL
+WebChart = http://www.gxchart.com/webchart.wsdl
+WebSearchWS = http://www.esynaps.com/WebServices/SearchWS.asmx?WSDL
+WhoIS = http://ws.cdyne.com/whoisquery/whois.asmx?wsdl
+WhoIsService = http://www.esynaps.com/WebServices/WhoIsService.asmx?WSDL
+XmlDailyFact = http://www.xmlme.com/WSDailyXml.asmx?WSDL
+XmlTracking = http://www.baxglobal.com/xmltracking/xmltracking.asmx?wsdl
+XreOnline = http://www.codecube.net/services/xreonline.asmx?WSDL
+ZipCodesService = http://webservices.instantlogic.com/zipcodes.ils?wsdl
+airport = http://www.webservicex.net/airport.asmx?wsdl
+bork = http://www.x-ws.de/cgi-bin/bork/service.wsdl
+chat = http://www.x-ws.de/cgi-bin/eliza/chat.wsdl
+country = http://www.webservicex.net/country.asmx?wsdl
+eSynapsFeed = http://www.esynaps.com/WebServices/eSynapsFeed.asmx?WSDL
+eSynapsSerach = http://www.esynaps.com/WebServices/eSynapsSearch.asmx?WSDL
+engtoarabic = http://www.dl-me.com/etoaservice/engtoarabic.asmx?WSDL
+fWArticleService = http://www.framewerks.com/WebServices/fWArticleService/fwArticles.asmx?WSDL
+fax = http://www.webservicex.net/fax.asmx?wsdl
+foxcentral = http://www.foxcentral.net/foxcentral.wsdl
+iifws = http://www.inkostar.com/wsdl/iifws/iifws.wsdl
+imstatus = http://www.x-ws.de/cgi-bin/msn/imstatus.wsdl
+periodictable = http://www.webservicex.net/periodictable.asmx?wsdl
+piglatin = http://www.aspxpressway.com/maincontent/webservices/piglatin.asmx?wsdl
+unitext = http://www.dl-me.com/webservices/unitext.asmx?wsdl
+wwhelpservice = http://www.west-wind.com/wconnect/soap/wwhelpservice.wsdl
+xmlserver = http://xml.redcoal.net/SMSSOAP/xmlserver.wsdl
+
+# complex types
+
+AddFinderService = http://www.lixusnet.com/lixusnet/AddFinder.jws?wsdl
+AddressFinder = http://arcweb.esri.com/services/v2/AddressFinder.wsdl
+AddressLookup = http://ws.cdyne.com/psaddress/addresslookup.asmx?wsdl
+AmazonQuery = http://majordojo.com/amazon_query/amazon_query.wsdl
+AmazonSearch = http://soap.amazon.com/schemas/AmazonWebServices.wsdl
+BondService = http://www.financialwebservices.ltd.uk/axis/services/bond?wsdl
+BusinessNews = http://glkev.webs.innerhost.com/glkev_ws/businessnews.asmx?WSDL
+CarRentalQuotesService = http://wavendon.dsdata.co.uk/axis/services/CarRentalQuotes?wsdl
+CupScores = http://scores.serviceobjects.com/CupScores.asmx?WSDL
+DOTSAddressValidate = http://ws2.serviceobjects.net/av/AddressValidate.asmx?WSDL
+DOTSDomainSpy = http://ws2.serviceobjects.net/ds/domainspy.asmx?WSDL
+DOTSEmailValidate = http://ws2.serviceobjects.net/ev/EmailValidate.asmx?WSDL
+DOTSFastQuote = http://ws2.serviceobjects.net/sq/FastQuote.asmx?WSDL
+DOTSFastTax = http://ws2.serviceobjects.net/ft/FastTax.asmx?WSDL
+DOTSFastWeather = http://ws2.serviceobjects.net/fw/FastWeather.asmx?WSDL
+DOTSGeoCash = http://ws2.serviceobjects.net/gc/GeoCash.asmx?WSDL
+DOTSGeoPhone = http://ws2.serviceobjects.net/gp/GeoPhone.asmx?WSDL
+DOTSGeoPinPoint = http://ws2.serviceobjects.net/gpp/GeoPinPoint.asmx?WSDL
+DOTSLotteryNumbers = http://ws2.serviceobjects.net/ln/lotterynumbers.asmx?WSDL
+DOTSPackageTracking = http://ws2.serviceobjects.net/pt/PackTrack.asmx?WSDL
+DOTSPatentOffice = http://ws2.serviceobjects.net/uspo/USPatentOffice.asmx?WSDL
+DOTSPhoneAppend = http://ws2.serviceobjects.net/pa/phoneappend.asmx?wsdl
+DOTSShippingComparison = http://ws2.serviceobjects.net/pc/packcost.asmx?WSDL
+DOTSUPC = http://ws2.serviceobjects.net/upc/UPC.asmx?WSDL
+DOTSYellowPages = http://ws2.serviceobjects.net/yp/YellowPages.asmx?WSDL
+Dispenser = http://www.blackstoneonline.com/webservices/dispenser.xml
+DocConverterService = http://telecommerce.danet.de/axis/services/DocConverterServicePort?wsdl
+FOPService = http://live.capescience.com/wsdl/FOPService.wsdl
+FedRoutingDirectoryService = http://demo.soapam.com/services/FedEpayDirectory/FedEpayDirectoryService.wsdl
+GMChart = http://service.graphmagic.com/GMService/GraphMagic.asmx?wsdl
+GeoPlaces = http://www.codebump.com/services/placelookup.asmx?wsdl
+GlobalWeather = http://live.capescience.com/wsdl/GlobalWeather.wsdl
+GoogleSearch = http://api.google.com/GoogleSearch.wsdl
+HPcatalogService = http://www.lixusnet.com/lixusnet/HPcatalog.jws?wsdl
+HTMLeMail = http://www.framewerks.com/WebServices/HTMLeMail/HTMLeMail.asmx?WSDL
+HelpfulFunctions = http://www.framewerks.com/WebServices/helpfulfunctions/helpfulfunctions.asmx?WSDL
+HistoricalStockQuotes = http://glkev.webs.innerhost.com/glkev_ws/HistoricalStockQuotes.asmx?WSDL
+Horoscope = http://www.swanandmokashi.com/HomePage/WebServices/Horoscope.asmx?WSDL
+IACHSOAPservice = http://soap.achchex.com/exec/achsoap.dll/wsdl/IACHSOAP
+IP2Geo = http://ws.cdyne.com/ip2geo/ip2geo.asmx?wsdl
+ISoapFindMP3service = http://www.agnisoft.com/soap/mssoapmp3search.xml
+ITeeChartservice = http://www.berneda.com/scripts/TeeChartSOAP.exe/wsdl/ITeeChart
+IZPOP3service = http://www.zanetti-dev.com/scripts/zpop3ws.exe/wsdl/IZPOP3
+LookyBookService = http://www.winisp.net/cheeso/books/books.asmx?WSDL
+MailLocate = http://www.maillocate.com/soap/index.php?wsdl
+NavBarServer = http://ws.xara.com/navbar/navbar.wsdl
+Online Messenger Service = http://www.nims.nl/soap/oms.wsdl
+OnlineMessengerService = http://www.nims.nl/soap/oms2.wsdl
+Option_x0020_Pricing_x0020_Calculator = http://www.indobiz.com/OptionPricing.asmx?WSDL
+PersonLookup = http://www.barnaland.is/dev/personlookup.asmx?WSDL
+Phonebook = http://www.barnaland.is/dev/phonebook.asmx?WSDL
+PopulationWS = http://www.abundanttech.com/webservices/population/population.wsdl
+QueryInterfaceService = http://www.transactionalweb.com/SOAP/globalskilocator.wsdl
+QuizService = http://java.rus.uni-stuttgart.de/quiz/quiz.wsdl
+QuoteOfTheDay = http://www.swanandmokashi.com/HomePage/WebServices/QuoteOfTheDay.asmx?WSDL
+RateInfoClass = http://www.xeeinc.com/RateInformation/RateInfo.asmx?WSDL
+RateInfoClass_1 = http://www.xeeinc.com/RateInformation/Rateinfo.asmx?WSDL
+RecipeService = http://icuisine.net/webservices/RecipeService.asmx?WSDL
+RenderServer3D = http://ws.xara.com/graphicrender/render3d.wsdl
+RichPayments = http://www.richsolutions.com/richpayments/richpay.asmx?WSDL
+SBGGetAirFareQuoteService = http://wavendon.dsdata.co.uk:8080/axis/services/SBGGetAirFareQuote?wsdl
+SMS = http://www.abctext.com/webservices/SMS.asmx?WSDL
+SalesRankNPrice = http://www.PerfectXML.NET/WebServices/SalesRankNPrice/BookService.asmx?WSDL
+SendSMS = http://www.webservicex.net/SendSMS.asmx?WSDL
+Server = http://addison.ra.cwru.edu/orc/calendar_copy/server.php?wsdl
+Service = http://www.ejse.com/WeatherService/Service.asmx?WSDL
+SpamKillerService = http://wavendon.dsdata.co.uk/axis/services/SpamKiller?wsdl
+StockQuotes = http://www.swanandmokashi.com/HomePage/WebServices/StockQuotes.asmx?WSDL
+TWSFissionDotNet = http://www.sidespace.com/ws/fission/fissiondotnet.php?wsdl
+TerraService = http://terraservice.net/TerraService.asmx?WSDL
+Transform = http://transform.dataconcert.com/transform.wsdl
+UPSTracking = http://glkev.webs.innerhost.com/glkev_ws/UPSTracking.asmx?WSDL
+URLjr_Library = http://urljr.com/soap
+WeatherFetcher = http://glkev.webs.innerhost.com/glkev_ws/WeatherFetcher.asmx?WSDL
+WeatherService = http://www.hkwizard.com/WeatherService.asmx?wsdl
+WebServiceOfTheDay = http://www.webserviceoftheday.com/ws/soap/wsotd.asmx?wsdl
+WeblogsSubscriber = http://soap.4s4c.com/weblogs/subscribe.wsdl
+WhoIs = http://ws2.serviceobjects.net/whi/WhoIs.asmx?WSDL
+WhoisDataService = http://wavendon.dsdata.co.uk/axis/services/WhoisData?wsdl
+WolframSearchService = http://webservices.wolfram.com/services/SearchServices/WolframSearch.wsdl
+XMethodsQuery = http://www.xmethods.net/wsdl/query.wsdl
+XigniteEdgar = http://www.xignite.com/xEdgar.asmx?WSDL
+XigniteNews = http://www.xignite.com/xnews.asmx?WSDL
+XigniteOptions = http://www.xignite.com/xoptions.asmx?WSDL
+XigniteQuotes = http://www.xignite.com/xquotes.asmx?WSDL
+XigniteRealTime = http://www.xignite.com/xrealtime.asmx?WSDL
+XigniteRetirement = http://www.xignite.com/xretirement.asmx?WSDL
+XigniteSecurity = http://www.xignite.com/xsecurity.asmx?WSDL
+XigniteSimulation = http://www.xignite.com/xsimulation.asmx?WSDL
+XigniteStatistics = http://www.xignite.com/xstatistics.asmx?WSDL
+XigniteSurvey = http://www.xignite.com/xSurvey.asmx?WSDL
+XigniteWorldNews = http://www.xignite.com/xworldnews.asmx?WSDL
+YourHost = http://www.esynaps.com/webservices/YourHostInfo.asmx?WSDL
+Zip2Geo = http://ws.cdyne.com/ziptogeo/zip2geo.asmx?wsdl
+ZipCode = http://www.ripedev.com/webservices/ZipCode.asmx?WSDL
+ZipCodeResolver = http://webservices.eraserver.net/zipcoderesolver/zipcoderesolver.asmx?WSDL
+ZipCodes = http://www.codebump.com/services/zipcodelookup.asmx?wsdl
+ZipcodeLookupService = http://www.winisp.net/cheeso/zips/ZipService.asmx?WSDL
+certServices = http://soapclient.com/xml/certService.wsdl
+check = http://ws.cdyne.com/SpellChecker/check.asmx?wsdl
+com.systinet.demo.freedb.FreeDBService = http://soap.systinet.net/demos/FreeDB/wsdl
+com.systinet.demo.ftp.FTPService = http://soap.systinet.net/demos/FTPService/wsdl
+com.systinet.demo.newsfeed.version1.NewsfeedService = http://soap.systinet.net/demos/Newsfeed/wsdl
+com.systinet.demo.rpmfind.RpmService = http://soap.systinet.net/demos/RpmFinder/wsdl
+com.systinet.demo.search.w3c.W3CSearchService = http://soap.systinet.net/demos/W3CSearch/wsdl
+com.systinet.demo.search.zvon.ZVONSearchService = http://soap.systinet.net/demos/ZVONSearch/wsdl
+dic2 = http://www.dl-me.com/webservices/dic2.asmx?WSDL
+eSynapsMonitor = http://www.esynaps.com/WebServices/eSynapsMonitor.wsdl
+ev = http://ws.cdyne.com/emailverify/ev.asmx?wsdl
+getQuakeDataService = http://webservices.tei.or.th/getQuakeData.cfc?wsdl
+getSessionReport = http://sandbox.grandcentral.com/services/reports?WSDL
+pwspNoCentrbankCurRates = http://server1.pointwsp.net/ws/finance/currency.asmx?WSDL
+sekeywordService = http://www.aspiringgeek.com/cfc/keyword/sekeyword.cfc?wsdl
+threatService = http://www.boyzoid.com/threat.cfc?wsdl
+xmethods_gcd = http://samples.bowstreet.com/bowstreet5/webengine/xmethods/gcd/Action!getWSDL
+
+
+
+##########################################################################
+# SECTION [reader_errors] -
+# unable to load file
+##########################################################################
+[reader_errors]
+
+BusinessFinder(UDDI)-WebService = http://www.esynaps.com/WebServices/BusinessList.asmx?WSDL
+ColdFusionTip-of-the-Day = http://www.forta.com/cf/tips/syndicate.cfc?wsdl
+ComputerDictionarySearch = http://dotnet.cyberthink.net/computerdictionary/computerdictionary.asmx?wsdl
+DynamicChartingofXMLData = http://webservices.isitedesign.com/ws/chartWS.cfc?wsdl
+EmailServices = http://soap.einsteinware.com/email/emailservices.asmx?WSDL
+ExpressionEvaluator = http://www.onepercentsoftware.com/axis/services/EvaluationService?wsdl
+FonttoGraphic = http://ws.cdyne.com/FontToGraphic/ftg.asmx?wsdl
+HolidayInformation = http://wsdl.wsdlfeeds.com/holidays.cfc?wsdl
+Html2Xml = http://www.dev1.eraserver.net/REFLECTIONIT/Html2xml.asmx?WSDL
+HuZip = http://www.c6.hu/ws/huzip.wsdl
+HuarananetPresstechnologynews = http://www22.brinkster.com/horaciovallejo/netpress1.asmx?wsdl
+InfosVille = http://www.dotnetisp.com/webservices/dotnetisp/ville.asmx?WSDL
+ItalianFiscalCode = http://www.pinellus.com/cfc/Cod_fiscale.cfc?wsdl
+LinearSystemsSolver = http://www.cs.fsu.edu/~engelen/lu.wsdl
+LiveScoreService = http://www.freshscore.com/service/FreshScoreLiveScores.asmx?WSDL
+LogFileParser = http://www.bitounis.com/W3CParser/LogFileParser.asmx?WSDL
+MP3.comMusicCharts = http://webservices.mp3.com/MP3Charts.wsdl
+MachNumberWebService = http://www.cgi101.com/~msmithso/wsdl/mach.wsdl
+MagicSquares = http://www.cs.fsu.edu/~engelen/magic.wsdl
+MysicSearchEngine = http://mysic.com/Webservices/MysicSearchEngine.asmx?WSDL
+NASCARWinstonCupStatistics = http://soap.einsteinware.com/nascar/nascardataservice.asmx?WSDL
+OpenDirectoryProject = http://wsdl.wsdlfeeds.com/odp.cfc?wsdl
+SchemaWebWebService = http://www.schemaweb.info/webservices/soap/SchemaWebSoap.asmx?wsdl
+SlashdotNewsFeed = http://webservices.isitedesign.com/ws/slashdotnews.cfc?wsdl
+SpamKiller = http://soap.prowizorka.com/spam/wsdl/ISpamCheck
+SpellCheck = http://www.worldwidedesktop.com/spellcheck/spellcheckservice.asmx?wsdl
+SpellChecker = http://wsdl.wsdlfeeds.com/spell.cfc?wsdl
+USAZipcodeInformation = http://www.webservicex.net/uszip.asmx?WSDL
+WebEvents = http://www.bitounis.com/WebEvents/events.asmx?WSDL
+WebRTF2HTML = http://www.infoaccelerator.net/cfc/rtf2html.cfc?WSDL
+cp2ville = http://www.dotnetisp.com/webservices/dotnetisp/codepostal.asmx?WSDL
+src2html = http://www.dotnetisp.com/webservices/dotnetisp/src2html.asmx?WSDL
--- /dev/null
+############################################################################
+# Joshua R. Boverhof, David W. Robertson, LBNL
+# See LBNLCopyright for copyright notice!
+###########################################################################
+import unittest
+import test_wsdl
+import utils
+
+def makeTestSuite():
+ suite = unittest.TestSuite()
+ suite.addTest(test_wsdl.makeTestSuite("services_by_file"))
+ return suite
+
+def main():
+ loader = utils.MatchTestLoader(True, None, "makeTestSuite")
+ unittest.main(defaultTest="makeTestSuite", testLoader=loader)
+
+if __name__ == "__main__" : main()
+
+
--- /dev/null
+#!/usr/bin/env python
+
+############################################################################
+# Joshua R. Boverhof, David W. Robertson, LBNL
+# See LBNLCopyright for copyright notice!
+###########################################################################
+
+import sys, unittest
+import ConfigParser
+import os
+from wstools.Utility import DOM
+from wstools.WSDLTools import WSDLReader
+from wstools.TimeoutSocket import TimeoutError
+
+from wstools import tests
+cwd = os.path.dirname(tests.__file__)
+
+class WSDLToolsTestCase(unittest.TestCase):
+
+ def __init__(self, methodName='runTest'):
+ unittest.TestCase.__init__(self, methodName)
+
+ def setUp(self):
+ self.path = nameGenerator.next()
+ print self.path
+ sys.stdout.flush()
+
+ def __str__(self):
+ teststr = unittest.TestCase.__str__(self)
+ if hasattr(self, "path"):
+ return "%s: %s" % (teststr, self.path )
+ else:
+ return "%s" % (teststr)
+
+ def checkWSDLCollection(self, tag_name, component, key='name'):
+ if self.wsdl is None:
+ return
+ definition = self.wsdl.document.documentElement
+ version = DOM.WSDLUriToVersion(definition.namespaceURI)
+ nspname = DOM.GetWSDLUri(version)
+ for node in DOM.getElements(definition, tag_name, nspname):
+ name = DOM.getAttr(node, key)
+ comp = component[name]
+ self.failUnlessEqual(eval('comp.%s' %key), name)
+
+ def checkXSDCollection(self, tag_name, component, node, key='name'):
+ for cnode in DOM.getElements(node, tag_name):
+ name = DOM.getAttr(cnode, key)
+ component[name]
+
+ def test_all(self):
+ try:
+ if self.path[:7] == 'http://':
+ self.wsdl = WSDLReader().loadFromURL(self.path)
+ else:
+ self.wsdl = WSDLReader().loadFromFile(self.path)
+
+ except TimeoutError:
+ print "connection timed out"
+ sys.stdout.flush()
+ return
+ except:
+ self.path = self.path + ": load failed, unable to start"
+ raise
+
+ try:
+ self.checkWSDLCollection('service', self.wsdl.services)
+ except:
+ self.path = self.path + ": wsdl.services"
+ raise
+
+ try:
+ self.checkWSDLCollection('message', self.wsdl.messages)
+ except:
+ self.path = self.path + ": wsdl.messages"
+ raise
+
+ try:
+ self.checkWSDLCollection('portType', self.wsdl.portTypes)
+ except:
+ self.path = self.path + ": wsdl.portTypes"
+ raise
+
+ try:
+ self.checkWSDLCollection('binding', self.wsdl.bindings)
+ except:
+ self.path = self.path + ": wsdl.bindings"
+ raise
+
+ try:
+ self.checkWSDLCollection('import', self.wsdl.imports, key='namespace')
+ except:
+ self.path = self.path + ": wsdl.imports"
+ raise
+
+ try:
+ for key in self.wsdl.types.keys():
+ schema = self.wsdl.types[key]
+ self.failUnlessEqual(key, schema.getTargetNamespace())
+
+ definition = self.wsdl.document.documentElement
+ version = DOM.WSDLUriToVersion(definition.namespaceURI)
+ nspname = DOM.GetWSDLUri(version)
+ for node in DOM.getElements(definition, 'types', nspname):
+ for snode in DOM.getElements(node, 'schema'):
+ tns = DOM.findTargetNS(snode)
+ schema = self.wsdl.types[tns]
+ self.schemaAttributesDeclarations(schema, snode)
+ self.schemaAttributeGroupDeclarations(schema, snode)
+ self.schemaElementDeclarations(schema, snode)
+ self.schemaTypeDefinitions(schema, snode)
+ except:
+ self.path = self.path + ": wsdl.types"
+ raise
+
+ if self.wsdl.extensions:
+ print 'No check for WSDLTools(%s) Extensions:' %(self.wsdl.name)
+ for ext in self.wsdl.extensions: print '\t', ext
+
+ def schemaAttributesDeclarations(self, schema, node):
+ self.checkXSDCollection('attribute', schema.attr_decl, node)
+
+ def schemaAttributeGroupDeclarations(self, schema, node):
+ self.checkXSDCollection('group', schema.attr_groups, node)
+
+ def schemaElementDeclarations(self, schema, node):
+ self.checkXSDCollection('element', schema.elements, node)
+
+ def schemaTypeDefinitions(self, schema, node):
+ self.checkXSDCollection('complexType', schema.types, node)
+ self.checkXSDCollection('simpleType', schema.types, node)
+
+
+def setUpOptions(section):
+ cp = ConfigParser.ConfigParser()
+ cp.read(cwd+'/config.txt')
+ if not cp.sections():
+ print 'fatal error: configuration file config.txt not present'
+ sys.exit(0)
+ if not cp.has_section(section):
+ print '%s section not present in configuration file, exiting' % section
+ sys.exit(0)
+ return cp, len(cp.options(section))
+
+def getOption(cp, section):
+ for name, value in cp.items(section):
+ yield value
+
+def makeTestSuite(section='services_by_file'):
+ global nameGenerator
+
+ cp, numTests = setUpOptions(section)
+ nameGenerator = getOption(cp, section)
+ suite = unittest.TestSuite()
+ for i in range(0, numTests):
+ suite.addTest(unittest.makeSuite(WSDLToolsTestCase, 'test_'))
+ return suite
+
+
+def main():
+ unittest.main(defaultTest="makeTestSuite")
+
+
+if __name__ == "__main__" : main()
--- /dev/null
+#!/usr/bin/env python
+
+############################################################################
+# Joshua R. Boverhof, David W. Robertson, LBNL
+# See LBNLCopyright for copyright notice!
+###########################################################################
+
+import unittest, tarfile, os, ConfigParser
+import test_wsdl
+
+
+SECTION='files'
+CONFIG_FILE = 'config.txt'
+
+def extractFiles(section, option):
+ config = ConfigParser.ConfigParser()
+ config.read(CONFIG_FILE)
+ archives = config.get(section, option)
+ archives = eval(archives)
+ for file in archives:
+ tar = tarfile.open(file)
+ if not os.access(tar.membernames[0], os.R_OK):
+ for i in tar.getnames():
+ tar.extract(i)
+
+def makeTestSuite():
+ suite = unittest.TestSuite()
+ suite.addTest(test_wsdl.makeTestSuite("services_by_file"))
+ return suite
+
+def main():
+ extractFiles(SECTION, 'archives')
+ unittest.main(defaultTest="makeTestSuite")
+
+if __name__ == "__main__" : main()
+
+
--- /dev/null
+#!/usr/bin/env python
+
+############################################################################
+# Joshua R. Boverhof, David W. Robertson, LBNL
+# See LBNLCopyright for copyright notice!
+###########################################################################
+import unittest
+import test_wsdl
+
+def makeTestSuite():
+ suite = unittest.TestSuite()
+ suite.addTest(test_wsdl.makeTestSuite("services_by_http"))
+ return suite
+
+def main():
+ unittest.main(defaultTest="makeTestSuite")
+
+if __name__ == "__main__" : main()
+
+