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" | |||
| 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" | |||
| PROPERTIES = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.wsdl" | |||
| class WSSE: | |||
| 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" | |||
| CORE = "http://www.globus.org/namespaces/2004/06/core" | |||
| 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 string, httplib, smtplib, urllib, socket, weakref | |||
| import xml.dom.minidom | |||
| from string import join, strip, split | |||
| from UserDict import UserDict | |||
| from StringIO import StringIO | |||
| from cStringIO import StringIO | |||
| from TimeoutSocket import TimeoutSocket, TimeoutError | |||
| from urlparse import urlparse | |||
| from httplib import HTTPConnection, HTTPSConnection | |||
| 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: | |||
| from xml.dom.ext import SplitQName | |||
| except: | |||
| @@ -46,13 +53,29 @@ except: | |||
| return | |||
| return tuple(l) | |||
| class NamespaceError(Exception): | |||
| """Used to indicate a Namespace Error.""" | |||
| class RecursionError(Exception): | |||
| """Used to indicate a HTTP redirect recursion.""" | |||
| pass | |||
| 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(%x)' %(module, self.__class__, id(self))) | |||
| class HTTPResponse: | |||
| """Captures the information in an HTTP response message.""" | |||
| @@ -586,11 +609,473 @@ class DOM: | |||
| file.close() | |||
| 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): | |||
| @@ -845,3 +1330,4 @@ if 1: | |||
| return clone | |||
| xml.dom.minidom._clone_node = _clone_node | |||
| @@ -9,11 +9,11 @@ | |||
| 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 Namespaces import WSR, WSA | |||
| from StringIO import StringIO | |||
| import urllib | |||
| class WSDLReader: | |||
| @@ -130,6 +130,39 @@ class WSDL: | |||
| 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) | |||
| # 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 | |||
| @@ -330,6 +363,7 @@ class Element: | |||
| self.extensions = [] | |||
| def addExtension(self, item): | |||
| item.parent = weakref.ref(self) | |||
| self.extensions.append(item) | |||
| @@ -338,6 +372,17 @@ class ImportElement(Element): | |||
| 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 | |||
| @@ -393,6 +438,19 @@ class Message(Element): | |||
| if elemref is not None: | |||
| 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): | |||
| def __init__(self, name): | |||
| @@ -416,6 +474,22 @@ class MessagePart(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 | |||
| @@ -455,8 +529,8 @@ class PortType(Element): | |||
| self.documentation = GetDocumentation(element) | |||
| 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) | |||
| NS_WSDL = DOM.GetWSDLUri(self.getWSDL().version) | |||
| @@ -501,6 +575,20 @@ class PortType(Element): | |||
| action = DOM.getAttr(item, 'Action', WSA.ADDRESS, None) | |||
| 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): | |||
| @@ -511,6 +599,10 @@ class Operation(Element): | |||
| 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() | |||
| @@ -553,12 +645,28 @@ class Operation(Element): | |||
| 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): | |||
| @@ -567,6 +675,22 @@ class MessageRole(Element): | |||
| self.type = type | |||
| 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): | |||
| def __init__(self, name, type, documentation=''): | |||
| @@ -641,6 +765,22 @@ class Binding(Element): | |||
| 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=''): | |||
| @@ -649,6 +789,11 @@ class OperationBinding(Element): | |||
| 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() | |||
| @@ -669,12 +814,14 @@ class OperationBinding(Element): | |||
| 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 | |||
| @@ -702,12 +849,34 @@ class OperationBinding(Element): | |||
| 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 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): | |||
| for item in self.extensions: | |||
| if isinstance(item, kind): | |||
| @@ -795,6 +964,15 @@ class MessageRoleBinding(Element): | |||
| 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=''): | |||
| @@ -826,12 +1004,25 @@ class Service(Element): | |||
| 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() | |||
| @@ -874,23 +1065,69 @@ class Port(Element): | |||
| 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): | |||
| @@ -905,6 +1142,17 @@ class SoapBodyBinding: | |||
| 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'): | |||
| @@ -3,10 +3,7 @@ | |||
| ident = "$Id$" | |||
| import WSDLTools | |||
| #import WSDLTools | |||
| import XMLname | |||
| 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 | |||