I've been playing with Zope and XML-RPC for a while and now I would like writing down part of my experiments. If you have a ZOPE running on your intranet and you are interested in sharing data with your own applications, you might be tempted to use Zope to do it.
Waiting for a good (official) support for SOAP in Zope, I decided to investigate what is possible to do using the XML-RPC protocol. I did several experiments and I found very little documentation about it in ZOPE. This is the reason I decided to write this little "how-to". Here is a short list of related documents:
Since it's quite easy to exchange basic data types like integer numbers and strings (real numbers have a different treatment) via XML-RPC, I want to focus here on something bit more complex: binary data.
Consider having some files in a folder called "repository", visible to Zope via LocalFS (search Zope website for more informations about it). What I want to do is download these files from my client application using XML-RPC. Lets "myfile.pdf" the file resident into your "repository" directory. What you need is:
Creating the server side script is quite easy: add a new Pyhton script "download" to your Zope accepting the "filename" parameter as input. The script should be something like this:
##parameters=filename
doc = {}
if hasattr(context.repository, filename):
# get the obj
doc['filename']=filename
obj = getattr(context.repository, filename)
doc['data']= context.base64_encodestring(obj.data)
return doc
this simple code looks into the "repository" folder for the "filename" file object. If the object exists this method returns a dictionary with two keys: "filename" containings the file name, and "data" containings the file contents base64-encoded.
Dues to some Zope restrictions we have to add an external method to be able to encode the string. This is easy: create an external method "base64_encodestring" linked to a python script "base64wrapper.py" with this simple content:
import base64
def base64_encodestring(s):
return base64.encodestring(s)
def base64_decodestring(s):
return base64.decodestring(s)
Now your server side script is done and working.
Creating a Python script ables to claim the file and save it in a local folder is a simple task.
import xmlrpclib
import base64
import os
def DownloadFile():
# connect to the server
ZopeServer=xmlrpclib.Server('http://localhost:8080/YourFolder')
# call method
dummy = ZopeServer.download('myfile.pdf')
# get 1st parameter: filename
filename = dummy['filename']
# get 2nd parameter: file data (base 64 encoded)
data = base64.decodestring(dummy['data'])
# create a temporary file
f = open('c:\\temp\\zope\\' + filename, 'wb')
f.write(data)
f.close()
where "YourFolder" is the Zope folder containings the script "download" providing the server side support. Replace "localhost" with your own Zope location as well as you can change the place where you write the new file.
The same way we did with Python we can build a little client for your VB application. Obviously you require a Visual Basic XML-RPC library in order to deal with Zope. I found a simple VB class providing all functionalities required. This class "ComXmlRpc" has been written by Ignacio Vazquez ivazquez@users.sourceforge.net and you can easily find it.
This library maps basic data between Python and Visual Basic in a straightforward way, a little note is necessary for complex data structures:
| Python | Visual Basic |
| tuples, lists | arrays |
| dictionaries | objects |
Private Sub DownloadFile()
Dim sDocument As String
sDocument = "myfile.pdf"
' Build a client
Dim xmlrpcserver As comxmlrpc.rpcClient
Dim params() As Variant
ReDim params(0)
params(0) = sDocument
'Build a server object
Set xmlrpcserver = New comxmlrpc.rpcClient
'Set the server uri
xmlrpcserver.uri = "http://localhost:8080/YourFolder"
'Call the method
Dim obj As Object
Set obj = xmlrpcserver.execute("download", params)
'Fetch data
Dim vFilename As Variant
Dim vData As Variant
vFilename = obj.Item("filename")
vData = obj.Item("data")
'Decode and make file
Dim objBase64 As Base64Lib.Base64
Set objBase64 = New Base64Lib.Base64
Call objBase64.DecodeToFile(CStr(vData), "C:\\Temp\\Zope\\" + vFilename)
End Sub
LUA is a lightweight programming language and, as well as Python, suitable for scripting. You will be able to find more complete details from the language website. Since we currently use this language in our company, I provide an example with this language to show how easy is to communicate between two scripting languages. As well as Python and VB, LUA requires some external modules able to understand XML-RPC. I used the XMLRPC module provided by Jay Carlson. The Lua clients sounds like this:
Lua doesn't make distinction between lists, tuples or dictionaries. The one and only native data structure for complex data is the "table" that can be compared to a Python dictionary (hash table, ...). The XMLRPC library is able to properly translate Python lists, tuples and dictionaries into Lua tables. Since the syntax is quite similar to Python I suppose you can guess what this function actually does.
function DownloadFile()
-- connect to the remote server
local ZopeServer = XMLRPC.Server('http://localhost:8080/YourFolder')
-- call the method
local res = ZopeServer.download('myfile.pdf')
-- get data
local filename = res['filename']
local data = res['data']
-- decode and save the file
local fn = openfile('c:\\temp\\zope\\' .. filename, 'wb')
write(fn, Code.unbase64(data))
closefile(fn)
end
The code in this document has been provided for didactical purpose only and it is not expected to work "as is". It requires support libraries, but you would be able to find all the necessary documentation about it in order to make it work. Also, as I stated at the beginning of this document, this is the result of my experiments. I'm sure there are several ways to do it in a different way.
Hope this helps.