# HG changeset patch # User paulb # Date 1191113720 0 # Node ID 51b2dda8c61b57671a008ac2ccbf6bcb86c94b30 # Parent 554e10bea4a315a16dec93abfd1162e9b075a686 [project @ 2007-09-30 00:55:20 by paulb] Added XML-RPC support. Made SOAP fault code access easier. diff -r 554e10bea4a3 -r 51b2dda8c61b libxml2dom/soap.py --- a/libxml2dom/soap.py Sat Sep 29 22:42:56 2007 +0000 +++ b/libxml2dom/soap.py Sun Sep 30 00:55:20 2007 +0000 @@ -229,7 +229,16 @@ "A SOAP subcode element." def _value(self): - return self.xpath("./env:Value")[0] + return self.xpath("./env:Value")[0].textContent.strip() + + def _setValue(self, value): + nodes = self.xpath("./env:Value") + v = self.createValue() + if nodes: + self.replaceChild(v, nodes[0]) + else: + self.appendChild(v) + v.value = value def createValue(self, value=None): code_value = self.ownerDocument.createElementNS(SOAP_ENVELOPE_NAMESPACE, "env:Value") @@ -237,7 +246,7 @@ code_value.value = code return code_value - value = property(_value) + value = property(_value, _setValue) class SOAPCodeElement(SOAPSubcodeElement): diff -r 554e10bea4a3 -r 51b2dda8c61b libxml2dom/xmlrpc.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxml2dom/xmlrpc.py Sun Sep 30 00:55:20 2007 +0000 @@ -0,0 +1,256 @@ +#!/usr/bin/env python + +""" +XML-RPC support using libxml2dom. + +See: http://www.xmlrpc.com/spec + +Copyright (C) 2007 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the Free +Software Foundation; either version 3 of the License, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. + +You should have received a copy of the GNU Lesser General Public License along +with this program. If not, see . + +-------- + +The sending and receiving of XML-RPC messages can be done using traditional HTTP +libraries. + +See tests/xmlrpc_test.py for more details. +""" + +import libxml2dom +from libxml2dom.macrolib import * +from libxml2dom.macrolib import \ + createDocument as Node_createDocument + +class XMLRPCImplementation(libxml2dom.Implementation): + + "Contains an XML-RPC-specific implementation." + + # Wrapping of documents. + + def adoptDocument(self, node): + return XMLRPCDocument(node, self) + + # Factory functions. + + def get_node(self, _node, context_node): + + """ + Get a libxml2dom node for the given low-level '_node' and libxml2dom + 'context_node'. + """ + + if Node_nodeType(_node) == context_node.ELEMENT_NODE: + + # Make special elements. + + if Node_localName(_node) in ("methodCall", "methodResponse"): + return XMLRPCMethodElement(_node, self, context_node.ownerDocument) + elif Node_localName(_node) == "methodName": + return XMLRPCMethodNameElement(_node, self, context_node.ownerDocument) + elif Node_localName(_node) == "fault": + return XMLRPCFaultElement(_node, self, context_node.ownerDocument) + elif Node_localName(_node) == "string": + return XMLRPCStringElement(_node, self, context_node.ownerDocument) + elif Node_localName(_node) in ("int", "i4"): + return XMLRPCIntegerElement(_node, self, context_node.ownerDocument) + elif Node_localName(_node) == "boolean": + return XMLRPCBooleanElement(_node, self, context_node.ownerDocument) + elif Node_localName(_node) == "double": + return XMLRPCDoubleElement(_node, self, context_node.ownerDocument) + elif Node_localName(_node) == "dateTime.iso8601": + return XMLRPCDateTimeElement(_node, self, context_node.ownerDocument) + elif Node_localName(_node) == "base64": + return XMLRPCBase64Element(_node, self, context_node.ownerDocument) + elif Node_localName(_node) == "struct": + return XMLRPCStructElement(_node, self, context_node.ownerDocument) + elif Node_localName(_node) == "member": + return XMLRPCMemberElement(_node, self, context_node.ownerDocument) + + # Otherwise, make generic XML-RPC elements. + + return XMLRPCElement(_node, self, context_node.ownerDocument) + + else: + return libxml2dom.Implementation.get_node(self, _node, context_node) + + # Convenience functions. + + def createXMLRPCMessage(self, namespaceURI, localName): + + "Create a new XML-RPC message document (fragment)." + + return XMLRPCDocument(Node_createDocument(namespaceURI, localName, None), self).documentElement + +# Node classes. + +class XMLRPCNode(libxml2dom.Node): + + "Convenience modifications to nodes specific to libxml2dom.xmlrpc." + + pass + +class XMLRPCDocument(libxml2dom._Document, XMLRPCNode): + + "An XML-RPC document fragment." + + def _method(self): + return self.xpath("./methodCall|./methodResponse")[0] + + method = property(_method) + +class XMLRPCElement(XMLRPCNode): + + "An XML-RPC element." + + pass + +class XMLRPCMethodElement(XMLRPCNode): + + "An XML-RPC method element." + + def _fault(self): + return self.xpath("./fault")[0] + + def _methodName(self): + return self.xpath("./methodName")[0] + + def _parameters(self): + return self.xpath("./params/param/value//*[not(./*)]") + + def _parameterValues(self): + values = {} + for parameter in self.parameters: + values[(parameter.namespaceURI, parameter.localName)] = parameter.textContent.strip() + return values + + def createFault(self): + return self.ownerDocument.createElement("fault") + + fault = property(_fault) + methodName = property(_methodName) + parameters = property(_parameters) + parameterValues = property(_parameterValues) + +class XMLRPCStringElement(XMLRPCNode): + + "An XML-RPC string element." + + def _value(self): + return self.textContent.strip() + + def _setValue(self, value): + for node in self.childNodes: + self.removeChild(node) + text = self.ownerDocument.createTextNode(value) + self.appendChild(text) + + value = property(_value, _setValue) + +class XMLRPCMethodNameElement(XMLRPCStringElement): + + "An XML-RPC method element." + + pass + +class XMLRPCIntegerElement(XMLRPCStringElement): + + "An XML-RPC integer element." + + pass + +class XMLRPCBooleanElement(XMLRPCStringElement): + + "An XML-RPC boolean element." + + pass + +class XMLRPCDoubleElement(XMLRPCStringElement): + + "An XML-RPC double floating point number element." + + pass + +class XMLRPCDateTimeElement(XMLRPCStringElement): + + "An XML-RPC date/time element." + + pass + +class XMLRPCBase64Element(XMLRPCStringElement): + + "An XML-RPC integer element." + + pass + +class XMLRPCStructElement(XMLRPCNode): + + "An XML-RPC structure element." + + def _members(self): + return self.xpath("./member") + + members = property(_members) + +class XMLRPCMemberElement(XMLRPCNode): + + "An XML-RPC structure member element." + + def _name(self): + return self.xpath("./name")[0].textContent.strip() + + def _value(self): + return self.xpath("./value")[0] + + name = property(_name) + value = property(_value) + +class XMLRPCFaultElement(XMLRPCNode): + + "An XML-RPC fault element." + + def _code(self): + return self.xpath("./value/struct/member[./name/text() = 'faultCode']/value/int")[0] + + def _reason(self): + return self.xpath("./value/struct/member[./name/text() = 'faultString']/value/string")[0] + + code = property(_code) + reason = property(_reason) + +# Utility functions. + +createDocument = libxml2dom.createDocument +createDocumentType = libxml2dom.createDocumentType + +def createXMLRPCMessage(namespaceURI, localName): + return default_impl.createXMLRPCMessage(namespaceURI, localName) + +def parse(stream_or_string, html=0, htmlencoding=None, unfinished=0, impl=None): + return libxml2dom.parse(stream_or_string, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl)) + +def parseFile(filename, html=0, htmlencoding=None, unfinished=0, impl=None): + return libxml2dom.parseFile(filename, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl)) + +def parseString(s, html=0, htmlencoding=None, unfinished=0, impl=None): + return libxml2dom.parseString(s, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl)) + +def parseURI(uri, html=0, htmlencoding=None, unfinished=0, impl=None): + return libxml2dom.parseURI(uri, html=html, htmlencoding=htmlencoding, unfinished=unfinished, impl=(impl or default_impl)) + +# Single instance of the implementation. + +default_impl = XMLRPCImplementation() + +# vim: tabstop=4 expandtab shiftwidth=4