import re from lxml import etree from PyQt4.QtXml import QDomDocument from sface.xmlwidget import XmlWindow, DomModel class XmlrpcReader(): def __init__(self): self.rawOutput = None self.responses = [] def getAndPrint(self, rawOutput): self.store(rawOutput) self.extractXml() self.xmlrpcWindow.setData(self.xml) if self.xml != "": # only popup the window if we have something to show self.showXmlrpc() def store(self, rawOutput): self.rawOutput = rawOutput def parseMethodResponse(self, mr): mr = str(mr) # PyQT supplies a QByteArray; make it a string response = {"kind": "unknown"} try: tree = etree.fromstring(mr) except etree.XMLSyntaxError, e: print "failed to parse XML response", str(e) #file("badparse.xml","w").write(mr) return response if tree.tag != "methodResponse" or (len(list(tree))==0): return response # a fault should look like: # kind: "fault" # faultCode: "102" # faultString: "Register: Missing authority..." faults = tree.xpath("//methodResponse/fault") for fault in faults: response["kind"] = "fault" structs = fault.xpath("value/struct") for struct in structs: members = struct.xpath("member") for member in members: names = member.xpath("name") values = member.xpath("value") if (names) and (values): name = names[0] value = values[0] if len(list(value))>0: data = list(value)[0] response[name.text] = data.text # once we have the first fault, return return response # whatever didn't fault must have succeeded? response["kind"] = "success" return response def extractXml(self): pttrnAsk = '.*?' pttrnAns = '.*?' answers = re.compile(pttrnAsk, re.DOTALL).findall(self.rawOutput) replies = re.compile(pttrnAns, re.DOTALL).findall(self.rawOutput) # cleaning answers = [ x.replace('\\n','\n') for x in answers ] replies = [ x.replace('\\n','\n').replace("'\nbody: '", '').replace("\"\nbody: '", '') for x in replies ] replies.reverse() # so that I use pop() as popleft # A well-formed XML document must have one, and only one, top-level element self.responses = [] self.xml = "" for ans in answers: self.xml += ans # we could have less responses than calls, so guard the pop if replies: replyXml = replies.pop() self.xml += replyXml self.responses.append(self.parseMethodResponse(replyXml)) # just in case somehow we ended up with more responses than calls while replies: replyXml = replies.pop() self.xml += replyXml self.responses.append(self.parseMethodResponse(replyXml)) return self.xml def stats(self): # statistics: round-trip time, size of the com pass class XmlrpcTracker(XmlrpcReader): def __init__(self): XmlrpcReader.__init__(self) self.xmlrpcWindow = XmlrpcWindow() def getAndPrint(self, rawOutput): self.store(rawOutput) self.extractXml() self.xmlrpcWindow.setData(self.xml) if self.xml != "": # only popup the window if we have something to show self.showXmlrpc() def showXmlrpc(self): self.xmlrpcWindow.show() self.xmlrpcWindow.resize(500, 640) self.xmlrpcWindow.raise_() self.xmlrpcWindow.activateWindow() def extractXml(self): self.xml = "" + XmlrpcReader.extractXml(self) + "" class XmlrpcWindow(XmlWindow): def __init__(self, parent=None): # super __init__() calls updateView, # which assumes you have some data self.data = '' XmlWindow.__init__(self, parent, 'XMLRPC window') def setData(self, XmlrpcCom): self.data = XmlrpcCom def updateView(self): XmlWindow.updateView(self) self.document.setContent(self.data)