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 |