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 |