Modified Files:
** removed all "imports" of ZSI or ZSI.wstools, so wstools
can be used independently by SOAPpy.
Namespaces.py
-- added a namespace
Utility.py
-- moved ZSI.utility here, and the "Base" class for logging.
WSDLTools.py
-- added a "toDom" and "GetWSDL" methods to several classes,
so now you can construct a WSDL instance and then call
WSDL.toDom() --> DOM --> and create a WSDL file.
__init__.py
-- removed "Base" class for logging.
Added Files:
c14n.py
-- moved the c14n stuff from ZSI.compat here.
----------------------------------------------------------------------
main
| @@ -75,6 +75,7 @@ class OASIS: | |||||
| WSSE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" | 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" | UTILITY = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" | ||||
| LIFETIME = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceLifetime-1.2-draft-01.xsd" | LIFETIME = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceLifetime-1.2-draft-01.xsd" | ||||
| PROPERTIES = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.wsdl" | |||||
| class WSSE: | class WSSE: | ||||
| BASE = "http://schemas.xmlsoap.org/ws/2002/04/secext" | BASE = "http://schemas.xmlsoap.org/ws/2002/04/secext" | ||||
| @@ -109,3 +110,5 @@ class GLOBUS: | |||||
| SECCONV = "http://wsrf.globus.org/core/2004/07/security/secconv" | SECCONV = "http://wsrf.globus.org/core/2004/07/security/secconv" | ||||
| CORE = "http://www.globus.org/namespaces/2004/06/core" | CORE = "http://www.globus.org/namespaces/2004/06/core" | ||||
| SIG = "http://www.globus.org/2002/04/xmlenc#gssapi-sign" | SIG = "http://www.globus.org/2002/04/xmlenc#gssapi-sign" | ||||
| ZSI_SCHEMA_URI = 'http://www.zolera.com/schemas/ZSI/' | |||||
| @@ -11,15 +11,22 @@ ident = "$Id$" | |||||
| import types | import types | ||||
| import string, httplib, smtplib, urllib, socket, weakref | import string, httplib, smtplib, urllib, socket, weakref | ||||
| import xml.dom.minidom | |||||
| from string import join, strip, split | from string import join, strip, split | ||||
| from UserDict import UserDict | from UserDict import UserDict | ||||
| from StringIO import StringIO | |||||
| from cStringIO import StringIO | |||||
| from TimeoutSocket import TimeoutSocket, TimeoutError | from TimeoutSocket import TimeoutSocket, TimeoutError | ||||
| from urlparse import urlparse | from urlparse import urlparse | ||||
| from httplib import HTTPConnection, HTTPSConnection | from httplib import HTTPConnection, HTTPSConnection | ||||
| from exceptions import Exception | from exceptions import Exception | ||||
| 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: | try: | ||||
| from xml.dom.ext import SplitQName | from xml.dom.ext import SplitQName | ||||
| except: | except: | ||||
| @@ -46,13 +53,29 @@ except: | |||||
| return | return | ||||
| return tuple(l) | return tuple(l) | ||||
| class NamespaceError(Exception): | |||||
| """Used to indicate a Namespace Error.""" | |||||
| class RecursionError(Exception): | class RecursionError(Exception): | ||||
| """Used to indicate a HTTP redirect recursion.""" | """Used to indicate a HTTP redirect recursion.""" | ||||
| pass | |||||
| class ParseError(Exception): | class ParseError(Exception): | ||||
| """Used to indicate a XML parsing error.""" | """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(%x)' %(module, self.__class__, id(self))) | |||||
| class HTTPResponse: | class HTTPResponse: | ||||
| """Captures the information in an HTTP response message.""" | """Captures the information in an HTTP response message.""" | ||||
| @@ -586,11 +609,473 @@ class DOM: | |||||
| file.close() | file.close() | ||||
| return result | return result | ||||
| DOM = DOM() | |||||
| class DOMException(Exception): | |||||
| pass | |||||
| 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 = sw | |||||
| def getSoapWriter(self, sw): | |||||
| return self._sw() | |||||
| def setSoapWriter(self, sw): | |||||
| self._sw = weakref.ref(sw) | |||||
| sw = property(getSoapWriter, setSoapWriter, None, "soap writer instance.") | |||||
| 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): | |||||
| prefix = self._soap_env_prefix | |||||
| if namespaceURI != self.reserved_ns[prefix]: | |||||
| raise KeyError, 'only support creation of document in %s' %self.reserved_ns[prefix] | |||||
| qualifiedName = '%s:%s' %(prefix,localName) | |||||
| 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) | |||||
| self._setAttributeNS(self._xsi_nsuri, '%s:type' %self._xsi_prefix, value) | |||||
| def createAttributeNS(self, namespace, name, value): | |||||
| document = self._getOwnerDocument() | |||||
| 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): | class Collection(UserDict): | ||||
| @@ -845,3 +1330,4 @@ if 1: | |||||
| return clone | return clone | ||||
| xml.dom.minidom._clone_node = _clone_node | xml.dom.minidom._clone_node = _clone_node | ||||
| @@ -9,11 +9,11 @@ | |||||
| ident = "$Id$" | ident = "$Id$" | ||||
| from Utility import DOM, Collection, CollectionNS | |||||
| import urllib, weakref | |||||
| from cStringIO import StringIO | |||||
| from Namespaces import OASIS, WSA, XMLNS | |||||
| from Utility import Collection, CollectionNS, DOM, ElementProxy | |||||
| from XMLSchema import XMLSchema, SchemaReader, WSDLToolsAdapter | from XMLSchema import XMLSchema, SchemaReader, WSDLToolsAdapter | ||||
| from Namespaces import WSR, WSA | |||||
| from StringIO import StringIO | |||||
| import urllib | |||||
| class WSDLReader: | class WSDLReader: | ||||
| @@ -130,6 +130,39 @@ class WSDL: | |||||
| self.imports[namespace] = item | self.imports[namespace] = item | ||||
| return 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) | |||||
| # 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): | def load(self, document): | ||||
| # We save a reference to the DOM document to ensure that elements | # We save a reference to the DOM document to ensure that elements | ||||
| # saved as "extensions" will continue to have a meaningful context | # saved as "extensions" will continue to have a meaningful context | ||||
| @@ -330,6 +363,7 @@ class Element: | |||||
| self.extensions = [] | self.extensions = [] | ||||
| def addExtension(self, item): | def addExtension(self, item): | ||||
| item.parent = weakref.ref(self) | |||||
| self.extensions.append(item) | self.extensions.append(item) | ||||
| @@ -338,6 +372,17 @@ class ImportElement(Element): | |||||
| self.namespace = namespace | self.namespace = namespace | ||||
| self.location = location | 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 | _loaded = None | ||||
| @@ -393,6 +438,19 @@ class Message(Element): | |||||
| if elemref is not None: | if elemref is not None: | ||||
| part.element = ParseTypeRef(elemref, element) | part.element = ParseTypeRef(elemref, element) | ||||
| 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): | class MessagePart(Element): | ||||
| def __init__(self, name): | def __init__(self, name): | ||||
| @@ -416,6 +474,22 @@ class MessagePart(Element): | |||||
| schema = wsdl.types.get(nsuri, {}) | schema = wsdl.types.get(nsuri, {}) | ||||
| return schema.get(name) | 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): | class PortType(Element): | ||||
| '''PortType has a anyAttribute, thus must provide for an extensible | '''PortType has a anyAttribute, thus must provide for an extensible | ||||
| @@ -455,8 +529,8 @@ class PortType(Element): | |||||
| self.documentation = GetDocumentation(element) | self.documentation = GetDocumentation(element) | ||||
| self.targetNamespace = DOM.getAttr(element, 'targetNamespace') | self.targetNamespace = DOM.getAttr(element, 'targetNamespace') | ||||
| if DOM.hasAttr(element, 'ResourceProperties', WSR.PROPERTIES): | |||||
| rpref = DOM.getAttr(element, 'ResourceProperties', WSR.PROPERTIES) | |||||
| if DOM.hasAttr(element, 'ResourceProperties', OASIS.PROPERTIES): | |||||
| rpref = DOM.getAttr(element, 'ResourceProperties', OASIS.PROPERTIES) | |||||
| self.resourceProperties = ParseQName(rpref, element) | self.resourceProperties = ParseQName(rpref, element) | ||||
| NS_WSDL = DOM.GetWSDLUri(self.getWSDL().version) | NS_WSDL = DOM.GetWSDLUri(self.getWSDL().version) | ||||
| @@ -501,6 +575,20 @@ class PortType(Element): | |||||
| action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None) | action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None) | ||||
| operation.addFault(message, name, docs, action) | 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(OASIS.PROPERTIES, 'ResourceProperties', '%s:%s'%(prefix,name)) | |||||
| for op in self.operations: | |||||
| op.toDom(epc._getNode()) | |||||
| class Operation(Element): | class Operation(Element): | ||||
| @@ -511,6 +599,10 @@ class Operation(Element): | |||||
| self.input = None | self.input = None | ||||
| self.output = None | self.output = None | ||||
| def getWSDL(self): | |||||
| """Return the WSDL object that contains this Operation.""" | |||||
| return self.parent().parent().parent().parent() | |||||
| def getPortType(self): | def getPortType(self): | ||||
| return self.parent().parent() | return self.parent().parent() | ||||
| @@ -553,12 +645,28 @@ class Operation(Element): | |||||
| def setInput(self, message, name='', documentation='', action=None): | def setInput(self, message, name='', documentation='', action=None): | ||||
| self.input = MessageRole('input', message, name, documentation, action) | self.input = MessageRole('input', message, name, documentation, action) | ||||
| self.input.parent = weakref.ref(self) | |||||
| return self.input | return self.input | ||||
| def setOutput(self, message, name='', documentation='', action=None): | def setOutput(self, message, name='', documentation='', action=None): | ||||
| self.output = MessageRole('output', message, name, documentation, action) | self.output = MessageRole('output', message, name, documentation, action) | ||||
| self.output.parent = weakref.ref(self) | |||||
| return self.output | 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): | class MessageRole(Element): | ||||
| def __init__(self, type, message, name='', documentation='', action=None): | def __init__(self, type, message, name='', documentation='', action=None): | ||||
| @@ -567,6 +675,22 @@ class MessageRole(Element): | |||||
| self.type = type | self.type = type | ||||
| self.action = action | self.action = action | ||||
| def getWSDL(self): | |||||
| """Return the WSDL object that contains this MessageRole.""" | |||||
| if self.parent().getWSDL() == 'fault': | |||||
| return self.parent().parent().getWSDL() | |||||
| return self.parent().getWSDL() | |||||
| def toDom(self, node): | |||||
| wsdl = self.getWSDL() | |||||
| ep = ElementProxy(None, node) | |||||
| epc = ep.createAppendElement(DOM.GetWSDLUri(wsdl.version), self.type) | |||||
| epc.setAttributeNS(None, 'message', self.message) | |||||
| if self.action: | |||||
| epc.setAttributeNS(WSA.ADDRESS2004, 'Action', self.action) | |||||
| class Binding(Element): | class Binding(Element): | ||||
| def __init__(self, name, type, documentation=''): | def __init__(self, name, type, documentation=''): | ||||
| @@ -641,6 +765,22 @@ class Binding(Element): | |||||
| else: | else: | ||||
| self.addExtension(e) | 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): | class OperationBinding(Element): | ||||
| def __init__(self, name, documentation=''): | def __init__(self, name, documentation=''): | ||||
| @@ -649,6 +789,11 @@ class OperationBinding(Element): | |||||
| self.output = None | self.output = None | ||||
| self.faults = Collection(self) | self.faults = Collection(self) | ||||
| def getWSDL(self): | |||||
| """Return the WSDL object that contains this binding.""" | |||||
| return self.parent().parent().parent().parent() | |||||
| def getBinding(self): | def getBinding(self): | ||||
| """Return the parent Binding object of the operation binding.""" | """Return the parent Binding object of the operation binding.""" | ||||
| return self.parent().parent() | return self.parent().parent() | ||||
| @@ -669,12 +814,14 @@ class OperationBinding(Element): | |||||
| def addInputBinding(self, binding): | def addInputBinding(self, binding): | ||||
| if self.input is None: | if self.input is None: | ||||
| self.input = MessageRoleBinding('input') | self.input = MessageRoleBinding('input') | ||||
| self.input.parent = weakref.ref(self) | |||||
| self.input.addExtension(binding) | self.input.addExtension(binding) | ||||
| return binding | return binding | ||||
| def addOutputBinding(self, binding): | def addOutputBinding(self, binding): | ||||
| if self.output is None: | if self.output is None: | ||||
| self.output = MessageRoleBinding('output') | self.output = MessageRoleBinding('output') | ||||
| self.output.parent = weakref.ref(self) | |||||
| self.output.addExtension(binding) | self.output.addExtension(binding) | ||||
| return binding | return binding | ||||
| @@ -702,12 +849,34 @@ class OperationBinding(Element): | |||||
| else: | else: | ||||
| self.addExtension(e) | 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): | class MessageRoleBinding(Element): | ||||
| def __init__(self, type, name='', documentation=''): | def __init__(self, type, name='', documentation=''): | ||||
| Element.__init__(self, name, documentation) | Element.__init__(self, name, documentation) | ||||
| self.type = type | self.type = type | ||||
| def getWSDL(self): | |||||
| """Return the WSDL object that contains this MessageRole.""" | |||||
| if self.type == 'fault': | |||||
| return self.parent().parent().getWSDL() | |||||
| return self.parent().getWSDL() | |||||
| def findBinding(self, kind): | def findBinding(self, kind): | ||||
| for item in self.extensions: | for item in self.extensions: | ||||
| if isinstance(item, kind): | if isinstance(item, kind): | ||||
| @@ -795,6 +964,15 @@ class MessageRoleBinding(Element): | |||||
| else: | else: | ||||
| self.addExtension(e) | 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): | class Service(Element): | ||||
| def __init__(self, name, documentation=''): | def __init__(self, name, documentation=''): | ||||
| @@ -826,12 +1004,25 @@ class Service(Element): | |||||
| for e in elements: | for e in elements: | ||||
| self.addExtension(e) | 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): | class Port(Element): | ||||
| def __init__(self, name, binding, documentation=''): | def __init__(self, name, binding, documentation=''): | ||||
| Element.__init__(self, name, documentation) | Element.__init__(self, name, documentation) | ||||
| self.binding = binding | self.binding = binding | ||||
| def getWSDL(self): | |||||
| return self.parent().parent().getWSDL() | |||||
| def getService(self): | def getService(self): | ||||
| """Return the Service object associated with this port.""" | """Return the Service object associated with this port.""" | ||||
| return self.parent().parent() | return self.parent().parent() | ||||
| @@ -874,23 +1065,69 @@ class Port(Element): | |||||
| else: | else: | ||||
| self.addExtension(e) | 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: | class SoapBinding: | ||||
| def __init__(self, transport, style='rpc'): | def __init__(self, transport, style='rpc'): | ||||
| self.transport = transport | self.transport = transport | ||||
| self.style = style | 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: | class SoapAddressBinding: | ||||
| def __init__(self, location): | def __init__(self, location): | ||||
| self.location = 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: | class SoapOperationBinding: | ||||
| def __init__(self, soapAction=None, style=None): | def __init__(self, soapAction=None, style=None): | ||||
| self.soapAction = soapAction | self.soapAction = soapAction | ||||
| self.style = style | 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: | class SoapBodyBinding: | ||||
| def __init__(self, use, namespace=None, encodingStyle=None, parts=None): | def __init__(self, use, namespace=None, encodingStyle=None, parts=None): | ||||
| @@ -905,6 +1142,17 @@ class SoapBodyBinding: | |||||
| self.parts = parts | self.parts = parts | ||||
| self.use = use | 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: | class SoapFaultBinding: | ||||
| def __init__(self, name, use, namespace=None, encodingStyle=None): | def __init__(self, name, use, namespace=None, encodingStyle=None): | ||||
| if not use in ('literal', 'encoded'): | if not use in ('literal', 'encoded'): | ||||
| @@ -3,10 +3,7 @@ | |||||
| ident = "$Id$" | ident = "$Id$" | ||||
| import WSDLTools | |||||
| #import WSDLTools | |||||
| import XMLname | import XMLname | ||||
| import logging | import logging | ||||
| class Base: | |||||
| def __init__(self, module=__name__): | |||||
| self.logger = logging.getLogger('%s-%s(%x)' %(module, self.__class__, id(self))) | |||||
| @@ -0,0 +1,505 @@ | |||||
| #! /usr/bin/env python | |||||
| """Compatibility module, imported by ZSI if you don't have PyXML 0.7. | |||||
| No copyright violations -- we're only using parts of PyXML that we | |||||
| wrote. | |||||
| """ | |||||
| from ZSI import _attrs, _children, _copyright | |||||
| _copyright += "\n\nPortions are also: " | |||||
| _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 | |||||
| ''' | |||||
| from xml.dom import Node | |||||
| from Namespaces import XMLNS | |||||
| import cStringIO as StringIO | |||||
| try: | |||||
| from xml.dom.ext import c14n | |||||
| except ImportError, ex: | |||||
| _implementation2 = None | |||||
| else: | |||||
| class _implementation2(c14n._implementation): | |||||
| """Patch for exclusive c14n | |||||
| """ | |||||
| def __init__(self, node, write, **kw): | |||||
| self.unsuppressedPrefixes = kw.get('unsuppressedPrefixes') | |||||
| self._exclusive = None | |||||
| if node.nodeType == Node.ELEMENT_NODE: | |||||
| if not c14n._inclusive(self): | |||||
| self._exclusive = self._inherit_context(node) | |||||
| c14n._implementation.__init__(self, node, write, **kw) | |||||
| def _do_element(self, node, initial_other_attrs = []): | |||||
| """Patch for the xml.dom.ext.c14n implemenation _do_element method. | |||||
| This fixes a problem with sorting of namespaces. | |||||
| """ | |||||
| # 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_parent, ns_rendered, xml_attrs = \ | |||||
| self.state[0], self.state[1].copy(), self.state[2].copy() #0422 | |||||
| ns_local = ns_parent.copy() | |||||
| xml_attrs_local = {} | |||||
| # Divide attributes into NS, XML, and others. | |||||
| #other_attrs = initial_other_attrs[:] | |||||
| other_attrs = [] | |||||
| sort_these_attrs = initial_other_attrs[:] | |||||
| in_subset = c14n._in_subset(self.subset, node) | |||||
| #for a in _attrs(node): | |||||
| sort_these_attrs +=c14n._attrs(node) | |||||
| for a in sort_these_attrs: | |||||
| if a.namespaceURI == c14n.XMLNS.BASE: | |||||
| n = a.nodeName | |||||
| if n == "xmlns:": n = "xmlns" # DOM bug workaround | |||||
| ns_local[n] = a.nodeValue | |||||
| elif a.namespaceURI == c14n.XMLNS.XML: | |||||
| if c14n._inclusive(self) or (in_subset and c14n._in_subset(self.subset, a)): #020925 Test to see if attribute node in subset | |||||
| xml_attrs_local[a.nodeName] = a #0426 | |||||
| else: | |||||
| if c14n._in_subset(self.subset, a): #020925 Test to see if attribute node in subset | |||||
| other_attrs.append(a) | |||||
| #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 | |||||
| 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 [ c14n.XMLNS.BASE, '' ] \ | |||||
| and ns_rendered.get('xmlns') in [ c14n.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() \ | |||||
| and (c14n._inclusive(self) or \ | |||||
| c14n._utilized(n, node, other_attrs, self.unsuppressedPrefixes)): | |||||
| ns_to_render.append((n, v)) | |||||
| ##################################### | |||||
| # JRB | |||||
| ##################################### | |||||
| if not c14n._inclusive(self): | |||||
| if node.prefix is None: | |||||
| look_for = [('xmlns', node.namespaceURI),] | |||||
| else: | |||||
| look_for = [('xmlns:%s' %node.prefix, node.namespaceURI),] | |||||
| for a in c14n._attrs(node): | |||||
| if a.namespaceURI != XMLNS.BASE: | |||||
| #print "ATTRIBUTE: ", (a.namespaceURI, a.prefix) | |||||
| if a.prefix: | |||||
| #print "APREFIX: ", a.prefix | |||||
| look_for.append(('xmlns:%s' %a.prefix, a.namespaceURI)) | |||||
| for key,namespaceURI in look_for: | |||||
| if ns_rendered.has_key(key): | |||||
| if ns_rendered[key] == namespaceURI: | |||||
| # Dont write out | |||||
| pass | |||||
| else: | |||||
| #ns_to_render += [(key, namespaceURI)] | |||||
| pass | |||||
| elif (key,namespaceURI) in ns_to_render: | |||||
| # Dont write out | |||||
| pass | |||||
| else: | |||||
| # Unique write out, rewrite to render | |||||
| ns_local[key] = namespaceURI | |||||
| for a in self._exclusive: | |||||
| if a.nodeName == key: | |||||
| #self._do_attr(a.nodeName, a.value) | |||||
| #ns_rendered[key] = namespaceURI | |||||
| #break | |||||
| ns_to_render += [(a.nodeName, a.value)] | |||||
| break | |||||
| elif key is None and a.nodeName == 'xmlns': | |||||
| #print "DEFAULT: ", (a.nodeName, a.value) | |||||
| ns_to_render += [(a.nodeName, a.value)] | |||||
| break | |||||
| #print "KEY: ", key | |||||
| else: | |||||
| #print "Look for: ", look_for | |||||
| #print "NS_TO_RENDER: ", ns_to_render | |||||
| #print "EXCLUSIVE NS: ", map(lambda f: (f.nodeName,f.value),self._exclusive) | |||||
| raise RuntimeError, \ | |||||
| 'can not find namespace (%s="%s") for exclusive canonicalization'\ | |||||
| %(key, namespaceURI) | |||||
| ##################################### | |||||
| # Sort and render the ns, marking what was rendered. | |||||
| ns_to_render.sort(c14n._sorter_ns) | |||||
| for n,v in ns_to_render: | |||||
| #XXX JRB, getting 'xmlns,None' here when xmlns='' | |||||
| if v: self._do_attr(n, v) | |||||
| else: | |||||
| v = '' | |||||
| 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 c14n._inclusive(self) or c14n._in_subset(self.subset,node.parentNode): #0426 | |||||
| other_attrs.extend(xml_attrs_local.values()) | |||||
| else: | |||||
| other_attrs.extend(xml_attrs.values()) | |||||
| #print "OTHER: ", other_attrs | |||||
| other_attrs.sort(c14n._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) | |||||
| for c in c14n._children(node): | |||||
| c14n._implementation.handlers[c.nodeType](self, c) | |||||
| self.state = state | |||||
| if name: W('</%s>' % name) | |||||
| c14n._implementation.handlers[c14n.Node.ELEMENT_NODE] = _do_element | |||||
| _IN_XML_NS = lambda n: n.namespaceURI == XMLNS.XML | |||||
| # 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 == node.prefix or n in unsuppressedPrefixes: return 1 | |||||
| for attr in other_attrs: | |||||
| if n == attr.prefix: return 1 | |||||
| return 0 | |||||
| _in_subset = lambda subset, node: not subset or node in subset | |||||
| # | |||||
| # JRB. Currently there is a bug in do_element, but since the underlying | |||||
| # Data Structures in c14n have changed I can't just apply the | |||||
| # _implementation2 patch above. But this will work OK for most uses, | |||||
| # just not XML Signatures. | |||||
| # | |||||
| 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') | |||||
| if self.subset: | |||||
| self.comments = kw.get('comments', 1) | |||||
| else: | |||||
| 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'], []) | |||||
| if node.nodeType == Node.DOCUMENT_NODE: | |||||
| self._do_document(node) | |||||
| elif node.nodeType == Node.ELEMENT_NODE: | |||||
| self.documentOrder = _Element # At document element | |||||
| if self.unsuppressedPrefixes is not None: | |||||
| self._do_element(node) | |||||
| 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 = node.data \ | |||||
| .replace("&", "&") \ | |||||
| .replace("<", "<") \ | |||||
| .replace(">", ">") \ | |||||
| .replace("\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 = value \ | |||||
| .replace("&", "&") \ | |||||
| .replace("<", "<") \ | |||||
| .replace('"', '"') \ | |||||
| .replace('\011', '	') \ | |||||
| .replace('\012', '
') \ | |||||
| .replace('\015', '
') | |||||
| W(s) | |||||
| W('"') | |||||
| def _do_element(self, node, initial_other_attrs = []): | |||||
| '''_do_element(self, node, initial_other_attrs = []) -> 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 | |||||
| # xml_attrs -- Attributes in XML namespace from parent | |||||
| # ns_local -- NS declarations relevant to this element | |||||
| ns_parent, ns_rendered, xml_attrs = \ | |||||
| self.state[0], self.state[1][:], self.state[2][:] | |||||
| ns_local = ns_parent.copy() | |||||
| # Divide attributes into NS, XML, and others. | |||||
| other_attrs = initial_other_attrs[:] | |||||
| in_subset = _in_subset(self.subset, node) | |||||
| for a in _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 self.unsuppressedPrefixes is None or in_subset: | |||||
| xml_attrs.append(a) | |||||
| else: | |||||
| other_attrs.append(a) | |||||
| # Render the node | |||||
| W, name = self.write, None | |||||
| if in_subset: | |||||
| name = node.nodeName | |||||
| W('<') | |||||
| W(name) | |||||
| # Create list of NS attributes to render. | |||||
| ns_to_render = [] | |||||
| for n,v in ns_local.items(): | |||||
| pval = ns_parent.get(n) | |||||
| # If default namespace is XMLNS.BASE or empty, skip | |||||
| if n == "xmlns" \ | |||||
| and v in [ XMLNS.BASE, '' ] and pval in [ XMLNS.BASE, '' ]: | |||||
| 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 == "xmlns:xml" \ | |||||
| and v in [ 'http://www.w3.org/XML/1998/namespace' ]: | |||||
| continue | |||||
| # If different from parent, or parent didn't render | |||||
| # and if not exclusive, or this prefix is needed or | |||||
| # not suppressed | |||||
| if (v != pval or n not in ns_rendered) \ | |||||
| and (self.unsuppressedPrefixes is None or \ | |||||
| _utilized(n, node, other_attrs, self.unsuppressedPrefixes)): | |||||
| ns_to_render.append((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.append(n) | |||||
| # Add in the XML attributes (don't pass to children, since | |||||
| # we're rendering them), sort, and render. | |||||
| other_attrs.extend(xml_attrs) | |||||
| xml_attrs = [] | |||||
| 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) | |||||
| 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: | |||||
| if _implementation2 is None: | |||||
| _implementation(node, output.write, **kw) | |||||
| else: | |||||
| apply(_implementation2, (node, output.write), kw) | |||||
| else: | |||||
| s = c14n.StringIO.StringIO() | |||||
| if _implementation2 is None: | |||||
| _implementation(node, s.write, **kw) | |||||
| else: | |||||
| apply(_implementation2, (node, s.write), kw) | |||||
| return s.getvalue() | |||||
| if __name__ == '__main__': print _copyright | |||||