XML-RPC HOWTO

Eric Kidd

Source Builders

eric.kidd@pobox.com

And Other Contributors

Copyright © 2001 by Eric Kidd

0.8.0, 2001-04-12
Revision History                                                             
Revision 0.8.0                             2001-04-12                        
Updated section on common interfaces. Added pointer to XML-RPC.Net           
information.                                                                 
Revision 0.7.0                             2001-04-03                        
Added section on C++ proxy classes.                                          
Revision 0.6.0                             2001-02-02                        
Added sections on Ruby, K and common interfaces.                             
Revision 0.5.0                             2001-01-23                        
Initial version.                                                             


Describes how to use XML-RPC to implement clients and servers in a variety of
languages. Provides example code in Perl, Python, C, C++, Java, PHP and other
languages. Includes sections on Zope and KDE 2.0. Applies to all operating
systems with XML-RPC support.

-----------------------------------------------------------------------------
Table of Contents
1. Legal Notice
2. What is XML-RPC?
    2.1. How it Works
    2.2. Supported Data Types
    2.3. The History of XML-RPC
   
   
3. XML-RPC vs. Other Protocols
    3.1. XML-RPC vs. CORBA
    3.2. XML-RPC vs. DCOM
    3.3. XML-RPC vs. SOAP
   
   
4. Common XML-RPC Interfaces
    4.1. Introspection: Discovering Server APIs
    4.2. Boxcarring: Sending Multiple Requests at Once
   
   
5. A Sample API: sumAndDifference
6. Using XML-RPC with Perl
    6.1. A Perl Client
    6.2. A Stand-Alone Perl Server
    6.3. A CGI-Based Perl Server
   
   
7. Using XML-RPC with Python
    7.1. A Python Client
   
   
8. Using XML-RPC with C and C++
    8.1. A C Client
    8.2. A C++ Client
    8.3. A C++ Client with Proxy Classes
    8.4. A CGI-Based C Server
   
   
9. Using XML-RPC with Java
    9.1. A Java Client
    9.2. A Stand-Alone Java Server
   
   
10. Using XML-RPC with PHP
    10.1. A PHP Client
    10.2. A PHP Server
   
   
11. Using XML-RPC with Microsoft .NET
12. Using XML-RPC with Ruby
    12.1. A Ruby Client
    12.2. A Ruby Server
   
   
13. Using XML-RPC with Proprietary Languages
    13.1. Using XML-RPC with K
   
   
14. Applications with Built-in XML-RPC Support
    14.1. Zope
    14.2. KDE 2.0
   
   
15. About This Document
    15.1. New Versions of This Document
    15.2. Contributors to the XML-RPC HOWTO
    15.3. Submitting Other Snippets
   
   

-----------------------------------------------------------------------------
1. Legal Notice

Permission is granted to copy, distribute and/or modify this document under
the terms of the GNU Free Documentation License, Version 1.1 or any later
version published by the Free Software Foundation with no Invariant Sections,
no Front-Cover Texts, and no Back-Cover Texts. You may obtain a copy of the
GNU Free Documentation License from the Free Software Foundation by visiting
[http://www.fsf.org/] their Web site or by writing to: Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

This manual contains short example programs ("the Software"). Permission is
hereby granted, free of charge, to any person obtaining a copy of the
Software, to deal in the Software without restriction, including without
limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following condition:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-----------------------------------------------------------------------------

2. What is XML-RPC?

[http://www.xmlrpc.com/] XML-RPC is a simple, portable way to make remote
procedure calls over HTTP. It can be used with Perl, Java, Python, C, C++,
PHP and many other programming languages. Implementations are available for
Unix, Windows and the Macintosh.

Here's a short XML-RPC client written in Perl. (We use Ken MacLeod's [http://
bitsko.slc.ut.us/~ken/xml-rpc/] Frontier::Client module.)
use Frontier::Client;                                                        
$server = Frontier::Client->new(url => 'http://betty.userland.com/RPC2');    
$name = $server->call('examples.getStateName', 41);                          
print "$name\n";                                                             

When run, this program will connect to the remote server, get the state name,
and print it. (State #41 should be South Dakota in this example.)

Here's the same program in Python. (This time, we use Fredrik Lundh's [http:/
/www.pythonware.com/products/xmlrpc/] xmlrpclib.)
python> import xmlrpclib                                                     
python> server = xmlrpclib.Server("http://betty.userland.com/RPC2")          
python> server.examples.getStateName(41)                                     
'South Dakota'                                                               

In the following chapters, you'll learn how to write XML-RPC clients and
servers in a variety of programming languages.
-----------------------------------------------------------------------------

2.1. How it Works

XML-RPC is described fully in Dave Winer's [http://www.xmlrpc.com/spec]
official specification. If you're curious, go ahead and take a look??it's a
quick and straight-forward read.

On the wire, XML-RPC values are encoded as XML:
<methodCall>                                                                 
  <methodName>sample.sumAndDifference</methodName>                           
  <params>                                                                   
    <param><value><int>5</int></value></param>                               
    <param><value><int>3</int></value></param>                               
  </params>                                                                  
</methodCall>                                                                

This is verbose, but compresses readily. It's also faster than you might
expect??according to measurements by Rick Blair, a round-trip XML-RPC call
takes 3 milliseconds using Hannes Wallnöfer's Java implementation.
-----------------------------------------------------------------------------

2.2. Supported Data Types

XML-RPC supports the following data types:

int
    A signed, 32-bit integer.
   
string
    An ASCII string, which may contain NULL bytes. (Actually, several XML-RPC
    implementations support Unicode, thanks to the underlying features of
    XML.)
   
boolean
    Either true or false.
   
double
    A double-precision floating point number. (Accuracy may be limited in
    some implementations.)
   
dateTime.iso8601
    A date and time. Unfortunately, since XML-RPC forbids the use of
    timezones, this is very nearly useless.
   
base64
    Raw binary data of any length; encoded using Base64 on the wire. Very
    useful. (Some implementations don't like to receive zero bytes of data,
    though.)
   
array
    An one-dimensional array of values. Individual values may be of any type.
   
struct
    A collection of key-value pairs. The keys are strings; the values may be
    of any type.
   

-----------------------------------------------------------------------------
2.3. The History of XML-RPC

XML-RPC was inspired by two earlier protocols. The first is an anonymous RPC
protocol designed by Dave Winer and announced in an old DaveNet essay. (This
is why XML-RPC servers are often installed under /RPC2.) The other, more
important inspiration was an early draft of the SOAP protocol.

A longer history of XML-RPC has been generously provided by Dave Winer. This
also explains the relationship between XML-RPC and SOAP.
-----------------------------------------------------------------------------

3. XML-RPC vs. Other Protocols

XML-RPC is not the only way to make remote procedure calls. Other popular
protocols include CORBA, DCOM and SOAP. Each of these protocols has
advantages and disadvantages.

The opinions in the section are obviously biased; please take them with a
grain of salt.
-----------------------------------------------------------------------------

3.1. XML-RPC vs. CORBA

[http://www.corba.org/] CORBA is a popular protocol for writing distributed,
object-oriented applications. It's typically used in multi-tier enterprise
applications. Recently, it's also been adopted by the [http://www.gnome.org/]
Gnome project for interapplication communication.

CORBA is well-supported by many vendors and several free software projects.
CORBA works well with Java and C++, and is available for many other
languages. CORBA also provides an excellent interface definition language
(IDL), allowing you to define readable, object-oriented APIs.

Unfortunately, CORBA is very complex. It has a steep learning curve, requires
significant effort to implement, and requires fairly sophisticated clients.
It's better-suited to enterprise and desktop applications than it is to
distributed web applications.
-----------------------------------------------------------------------------

3.2. XML-RPC vs. DCOM

[http://www.microsoft.com/com/tech/DCOM.asp] DCOM is Microsoft's answer to
CORBA. It's great if you're already using COM components, and you don't need
to talk to non-Microsoft systems. Otherwise, it won't help you very much.
-----------------------------------------------------------------------------

3.3. XML-RPC vs. SOAP

[http://www.w3.org/TR/SOAP/] SOAP is very similar to XML-RPC. It, too, works
by marshaling procedure calls over HTTP as XML documents. Unfortunately, SOAP
appears to be suffering from specification creep.

SOAP was originally created as a collaboration between UserLand,
DevelopMentor and Microsoft. The initial public release was basically XML-RPC
with namespaces and longer element names. Since then, however, SOAP has been
turned over a W3C working group.

Unfortunately, the working group has been adding a laundry-list of strange
features to SOAP. As of the current writing, SOAP supports XML Schemas,
enumerations, strange hybrids of structs and arrays, and custom types. At the
same time, several aspects of SOAP are implementation defined.

Basically, if you like XML-RPC, but wish the protocol had more features,
check out SOAP. :-)
-----------------------------------------------------------------------------

4. Common XML-RPC Interfaces

Several XML-RPC servers provide built-in methods. These aren't part of
XML-RPC itself, but they make handy add-ons.
-----------------------------------------------------------------------------

4.1. Introspection: Discovering Server APIs

Edd Dumbill [http://xmlrpc.usefulinc.com/doc/reserved.html] proposed the
following set of methods:
array system.listMethods ()                                                  
string system.methodHelp (string methodName)                                 
array system.methodSignature (string methodName)                             

If a server supports these methods, you can ask it to print out some
documentation:
import xmlrpclib                                                             
server = xmlrpclib.Server("http://xmlrpc-c.sourceforge.net/api/sample.php")  
for method in server.system.listMethods():                                   
    print method                                                             
    print server.system.methodHelp(method)                                   
    print                                                                    

These methods are currently supported by servers written in PHP, C and
Microsoft .NET. Partial introspection support is included in recent updates
to UserLand Frontier. Introspection support for Perl, Python and Java is
available at the XML-RPC Hacks page. Please feel free to add introspection
support to other XML-RPC servers!

Various client-side tools (documentation generators, wrapper generators, and
so on) can be found at the XML-RPC Hacks page as well.
-----------------------------------------------------------------------------

4.2. Boxcarring: Sending Multiple Requests at Once

If you're writing an XML-RPC client which makes lots of small function calls,
you may discover that your round-trip time is fairly high, thanks to Internet
backbone latency. Some servers allow you to batch up multiple requests using
the following function:
array system.multicall (array calls)                                         

You can find more information in the system.multicall RFC.

This method is currently supported by servers written in C and UserLand
Frontier. Servers written in Python and Perl can use the code at the XML-RPC
Hacks page.
-----------------------------------------------------------------------------

5. A Sample API: sumAndDifference

To demonstrate XML-RPC, we implement the following API in as many languages
as possible.
struct sample.sumAndDifference (int x, int y)                                

This function takes two integers as arguments, and returns an XML-RPC <struct
> containing two elements:

sum
    The sum of the two integers.
   
difference
    The difference between the two integers.
   

It's not very useful, but it makes a nice example. :-)

This function (and others) are available using the URL http://
xmlrpc-c.sourceforge.net/api/sample.php. (This URL won't do anything in a
browser; it requires an XML-RPC client.)
-----------------------------------------------------------------------------

6. Using XML-RPC with Perl

Ken MacLeod has implemented XML-RPC for Perl. You can find his Frontier::RPC
module at his [http://bitsko.slc.ut.us/~ken/xml-rpc/] website or through
[http://www.cpan.org/] CPAN.

To install Frontier::RPC, download the package and compile it in the standard
fashion:
bash$ gunzip -c Frontier-RPC-0.07b1.tar.gz | tar xvf -                       
bash$ cd Frontier-RPC-0.07b1                                                 
bash$ perl Makefile.PL                                                       
bash$ make                                                                   
bash$ make test                                                              
bash$ su -c 'make install'                                                   

(The process will be slightly different on Windows systems, or if you don't
have root access. Consult your Perl documentation for details.)
-----------------------------------------------------------------------------

6.1. A Perl Client

The following program shows how to call an XML-RPC server from Perl:
use Frontier::Client;                                                        
                                                                             
# Make an object to represent the XML-RPC server.                            
$server_url = 'http://xmlrpc-c.sourceforge.net/api/sample.php';              
$server = Frontier::Client->new(url => $server_url);                         
                                                                             
# Call the remote server and get our result.                                 
$result = $server->call('sample.sumAndDifference', 5, 3);                    
$sum = $result->{'sum'};                                                     
$difference = $result->{'difference'};                                       
                                                                             
print "Sum: $sum, Difference: $difference\n";                                
-----------------------------------------------------------------------------

6.2. A Stand-Alone Perl Server

The following program shows how to write an XML-RPC server in Perl:
use Frontier::Daemon;                                                        
                                                                             
sub sumAndDifference {                                                       
    my ($x, $y) = @_;                                                        
    return {'sum' => $x + $y, 'difference' => $x - $y};                      
}                                                                            
                                                                             
# Call me as http://localhost:8080/RPC2                                      
$methods = {'sample.sumAndDifference' => \&sumAndDifference};                
Frontier::Daemon->new(LocalPort => 8080, methods => $methods)                
    or die "Couldn't start HTTP server: $!";                                 
-----------------------------------------------------------------------------

6.3. A CGI-Based Perl Server

Frontier::RPC2 doesn't provide built-in support for CGI-based servers. It 
does, however, provide most of the pieces you'll need.

Save the following code as sumAndDifference.cgi in your web server's cgi-bin
directory. (On Unix systems, you'll need to make it executable by typing
chmod +x sumAndDifference.cgi.)
#!/usr/bin/perl -w                                                           
                                                                             
use strict;                                                                  
use Frontier::RPC2;                                                          
                                                                             
sub sumAndDifference {                                                       
    my ($x, $y) = @_;                                                        
    return {'sum' => $x + $y, 'difference' => $x - $y};                      
}                                                                            
                                                                             
process_cgi_call({'sample.sumAndDifference' => \&sumAndDifference});         
                                                                             
                                                                             
#==========================================================================  
#  CGI Support                                                               
#==========================================================================  
#  Simple CGI support for Frontier::RPC2. You can copy this into your CGI    
#  scripts verbatim, or you can package it into a library.                   
#  (Based on xmlrpc_cgi.c by Eric Kidd <http://xmlrpc-c.sourceforge.net/>.)  
                                                                             
# Process a CGI call.                                                        
sub process_cgi_call ($) {                                                   
    my ($methods) = @_;                                                      
                                                                             
    # Get our CGI request information.                                       
    my $method = $ENV{'REQUEST_METHOD'};                                     
    my $type = $ENV{'CONTENT_TYPE'};                                         
    my $length = $ENV{'CONTENT_LENGTH'};                                     
                                                                             
    # Perform some sanity checks.                                            
    http_error(405, "Method Not Allowed") unless $method eq "POST";          
    http_error(400, "Bad Request") unless $type eq "text/xml";               
    http_error(411, "Length Required") unless $length > 0;                   
                                                                             
    # Fetch our body.                                                        
    my $body;                                                                
    my $count = read STDIN, $body, $length;                                  
    http_error(400, "Bad Request") unless $count == $length;                 
                                                                             
    # Serve our request.                                                     
    my $coder = Frontier::RPC2->new;                                         
    send_xml($coder->serve($body, $methods));                                
}                                                                            
                                                                             
# Send an HTTP error and exit.                                               
sub http_error ($$) {                                                        
    my ($code, $message) = @_;                                               
    print <<"EOD";                                                           
Status: $code $message                                                       
Content-type: text/html                                                      
                                                                             
<title>$code $message</title>                                                
<h1>$code $message</h1>                                                      
<p>Unexpected error processing XML-RPC request.</p>                          
EOD                                                                          
    exit 0;                                                                  
}                                                                            
                                                                             
# Send an XML document (but don't exit).                                     
sub send_xml ($) {                                                           
    my ($xml_string) = @_;                                                   
    my $length = length($xml_string);                                        
    print <<"EOD";                                                           
Status: 200 OK                                                               
Content-type: text/xml                                                       
Content-length: $length                                                      
                                                                             
EOD                                                                          
    # We want precise control over whitespace here.                          
    print $xml_string;                                                       
}                                                                            

You can copy the utility routines into your own CGI scripts.
-----------------------------------------------------------------------------

7. Using XML-RPC with Python

Fredrik Lundh has provided an excellent XML-RPC library for Python.

To install, download the latest version. You can either stick the *.py files
in the same directory as your Python code, or you can install them in your
system's Python directory.

RedHat 6.2 users can type the following:
bash$ mkdir xmlrpclib-0.9.8                                                  
bash$ cd xmlrpclib-0.9.8                                                     
bash$ unzip ../xmlrpc-0.9.8-990621.zip                                       
bash$ python                                                                 
python> import xmlrpclib                                                     
python> import xmlrpcserver                                                  
python> Control-D                                                            
bash$ su -c 'cp *.py *.pyc /usr/lib/python1.5/'                              

We import two of the *.py files to trick Python into compiling them. Users of
other platforms should consult their Python documentation.

For more Python examples, see the article XML-RPC: It Works Both Ways on the
O'Reilly Network.
-----------------------------------------------------------------------------

7.1. A Python Client

The following program shows how to call an XML-RPC server from Python:
import xmlrpclib                                                             
                                                                             
# Create an object to represent our server.                                  
server_url = 'http://xmlrpc-c.sourceforge.net/api/sample.php';               
server = xmlrpclib.Server(server_url);                                       
                                                                             
# Call the server and get our result.                                        
result = server.sample.sumAndDifference(5, 3)                                
print "Sum:", result['sum']                                                  
print "Difference:", result['difference']                                    
-----------------------------------------------------------------------------

8. Using XML-RPC with C and C++

To get a copy of XML-RPC for C/C++, see the [http://xmlrpc-c.sourceforge.net]
xmlrpc-c website.

You can either download everything in RPM format, or you can build it from
source.
-----------------------------------------------------------------------------

8.1. A C Client

Save the following code in a file called getSumAndDifference.c:
#include <stdio.h>                                                           
#include <xmlrpc.h>                                                          
#include <xmlrpc_client.h>                                                   
                                                                             
#define NAME       "XML-RPC getSumAndDifference C Client"                    
#define VERSION    "0.1"                                                     
#define SERVER_URL "http://xmlrpc-c.sourceforge.net/api/sample.php"          
                                                                             
void die_if_fault_occurred (xmlrpc_env *env)                                 
{                                                                            
    /* Check our error-handling environment for an XML-RPC fault. */         
    if (env->fault_occurred) {                                               
        fprintf(stderr, "XML-RPC Fault: %s (%d)\n",                          
                env->fault_string, env->fault_code);                         
        exit(1);                                                             
    }                                                                        
}                                                                            
                                                                             
int main (int argc, char** argv)                                             
{                                                                            
    xmlrpc_env env;                                                          
    xmlrpc_value *result;                                                    
    xmlrpc_int32 sum, difference;                                            
                                                                             
    /* Start up our XML-RPC client library. */                               
    xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION);               
    xmlrpc_env_init(&env);                                                   
                                                                             
    /* Call our XML-RPC server. */                                           
    result = xmlrpc_client_call(&env, SERVER_URL,                            
                                "sample.sumAndDifference", "(ii)",           
                                (xmlrpc_int32) 5,                            
                                (xmlrpc_int32) 3);                           
    die_if_fault_occurred(&env);                                             
                                                                             
    /* Parse our result value. */                                            
    xmlrpc_parse_value(&env, result, "{s:i,s:i,*}",                          
                       "sum", &sum,                                          
                       "difference", &difference);                           
    die_if_fault_occurred(&env);                                             
                                                                             
    /* Print out our sum and difference. */                                  
    printf("Sum: %d, Difference: %d\n", (int) sum, (int) difference);        
                                                                             
    /* Dispose of our result value. */                                       
    xmlrpc_DECREF(result);                                                   
                                                                             
    /* Shutdown our XML-RPC client library. */                               
    xmlrpc_env_clean(&env);                                                  
    xmlrpc_client_cleanup();                                                 
                                                                             
    return 0;                                                                
}                                                                            

To compile it, you can type:
bash$ CLIENT_CFLAGS=`xmlrpc-c-config libwww-client --cflags`                      
bash$ CLIENT_LIBS=`xmlrpc-c-config libwww-client --libs`                          
bash$ gcc $CLIENT_CFLAGS -o getSumAndDifference getSumAndDifference.c $CLIENT_LIBS

You may need to replace gcc with the name of your system's C compiler.
-----------------------------------------------------------------------------

8.2. A C++ Client

Save the following code in a file called getSumAndDifference2.cc:
#include <iostream.h>                                                         
#include <XmlRpcCpp.h>                                                        
                                                                              
#define NAME       "XML-RPC getSumAndDifference C++ Client"                   
#define VERSION    "0.1"                                                      
#define SERVER_URL "http://xmlrpc-c.sourceforge.net/api/sample.php"           
                                                                              
static void get_sum_and_difference () {                                       
                                                                              
    // Build our parameter array.                                             
    XmlRpcValue param_array = XmlRpcValue::makeArray();                       
    param_array.arrayAppendItem(XmlRpcValue::makeInt(5));                     
    param_array.arrayAppendItem(XmlRpcValue::makeInt(3));                     
                                                                              
    // Create an object to resprent the server, and make our call.            
    XmlRpcClient server (SERVER_URL);                                         
    XmlRpcValue result = server.call("sample.sumAndDifference", param_array); 
                                                                              
    // Extract the sum and difference from our struct.                        
    XmlRpcValue::int32 sum = result.structGetValue("sum").getInt();           
    XmlRpcValue::int32 diff = result.structGetValue("difference").getInt();   
                                                                              
    cout << "Sum: " << sum << ", Difference: " << diff << endl;               
}                                                                             
                                                                              
int main (int argc, char **argv) {                                            
                                                                              
    // Start up our client library.                                           
    XmlRpcClient::Initialize(NAME, VERSION);                                  
                                                                              
    // Call our client routine, and watch out for faults.                     
    try {                                                                     
        get_sum_and_difference();                                             
    } catch (XmlRpcFault& fault) {                                            
        cerr << argv[0] << ": XML-RPC fault #" << fault.getFaultCode()        
             << ": " << fault.getFaultString() << endl;                       
        XmlRpcClient::Terminate();                                            
        exit(1);                                                              
    }                                                                         
                                                                              
    // Shut down our client library.                                          
    XmlRpcClient::Terminate();                                                
    return 0;                                                                 
}                                                                             

To compile it, you can type:
bash$ CLIENT_CFLAGS=`xmlrpc-c-config c++ libwww-client --cflags`                     
bash$ CLIENT_LIBS=`xmlrpc-c-config c++ libwww-client --libs`                         
bash$ c++ $CLIENT_CFLAGS -o getSumAndDifference2 getSumAndDifference2.cc $CLIENT_LIBS

You'll need a reasonably modern C++ compiler for this to work.
-----------------------------------------------------------------------------

8.3. A C++ Client with Proxy Classes

If your XML-RPC server supports the Introspection API, you can automatically
generate C++ proxy classes for it. To generate a proxy class, type the
following command and save the output to a file:
bash$ xml-rpc-api2cpp \                                                      
> http://xmlrpc-c.sourceforge.net/api/sample.php sample SampleProxy          

This will generate a proxy class named SampleProxy containing wrappers for
all the methods beginning with sample. You can edit this class in any fashion
you'd like.
-----------------------------------------------------------------------------

8.4. A CGI-Based C Server

Save the following code in a file called sumAndDifference.c:
#include <xmlrpc.h>                                                            
#include <xmlrpc_cgi.h>                                                        
                                                                               
xmlrpc_value *                                                                 
sumAndDifference (xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) 
{                                                                              
    xmlrpc_int32 x, y;                                                         
                                                                               
    /* Parse our argument array. */                                            
    xmlrpc_parse_value(env, param_array, "(ii)", &x, &y);                      
    if (env->fault_occurred)                                                   
        return NULL;                                                           
                                                                               
    /* Return our result. */                                                   
    return xmlrpc_build_value(env, "{s:i,s:i}",                                
                              "sum", x + y,                                    
                              "difference", x - y);                            
}                                                                              
                                                                               
int main (int argc, char **argv)                                               
{                                                                              
    /* Set up our CGI library. */                                              
    xmlrpc_cgi_init(XMLRPC_CGI_NO_FLAGS);                                      
                                                                               
    /* Install our only method (with a method signature and a help string). */ 
    xmlrpc_cgi_add_method_w_doc("sample.sumAndDifference",                     
                                &sumAndDifference, NULL,                       
                                "S:ii", "Add and subtract two integers.");     
                                                                               
    /* Call the appropriate method. */                                         
    xmlrpc_cgi_process_call();                                                 
                                                                               
    /* Clean up our CGI library. */                                            
    xmlrpc_cgi_cleanup();                                                      
}                                                                              

To compile it, you can type:
bash$ CGI_CFLAGS=`xmlrpc-c-config cgi-server --cflags`                       
bash$ CGI_LIBS=`xmlrpc-c-config cgi-server --libs`                           
bash$ gcc $CGI_CFLAGS -o sumAndDifference.cgi sumAndDifference.c $CGI_LIBS   

Once this is done, copy sumAndDifference.cgi into your webserver's cgi-bin
directory.
-----------------------------------------------------------------------------

9. Using XML-RPC with Java

Hannes Wallnöfer has provided an excellent implementation of XML-RPC for
Java.

To install it, download the distribution, unzip it, and add the *.jar files
to your CLASSPATH. On a Unix system, you can do this by typing:
bash$ unzip xmlrpc-java.zip                                                  
bash$ cd xmlrpc-java/lib                                                     
bash$ CLASSPATH=`pwd`/openxml-1.2.jar:`pwd`/xmlrpc.jar:$CLASSPATH            
-----------------------------------------------------------------------------

9.1. A Java Client

Save the following program in a file named JavaClient.java.
import java.util.Vector;                                                       
import java.util.Hashtable;                                                    
import helma.xmlrpc.*;                                                         
                                                                               
public class JavaClient {                                                      
                                                                               
    // The location of our server.                                             
    private final static String server_url =                                   
        "http://xmlrpc-c.sourceforge.net/api/sample.php";                      
                                                                               
    public static void main (String [] args) {                                 
        try {                                                                  
                                                                               
            // Create an object to represent our server.                       
            XmlRpcClient server = new XmlRpcClient(server_url);                
                                                                               
            // Build our parameter list.                                       
            Vector params = new Vector();                                      
            params.addElement(new Integer(5));                                 
            params.addElement(new Integer(3));                                 
                                                                               
            // Call the server, and get our result.                            
            Hashtable result =                                                 
                (Hashtable) server.execute("sample.sumAndDifference", params); 
            int sum = ((Integer) result.get("sum")).intValue();                
            int difference = ((Integer) result.get("difference")).intValue();  
                                                                               
            // Print out our result.                                           
            System.out.println("Sum: " + Integer.toString(sum) +               
                               ", Difference: " +                              
                               Integer.toString(difference));                  
                                                                               
        } catch (XmlRpcException exception) {                                  
            System.err.println("JavaClient: XML-RPC Fault #" +                 
                               Integer.toString(exception.code) + ": " +       
                               exception.toString());                          
        } catch (Exception exception) {                                        
            System.err.println("JavaClient: " + exception.toString());         
        }                                                                      
    }                                                                          
}                                                                              
-----------------------------------------------------------------------------

9.2. A Stand-Alone Java Server

Save the following program in a file named JavaServer.java.
import java.util.Hashtable;                                                  
import helma.xmlrpc.*;                                                       
                                                                             
public class JavaServer {                                                    
                                                                             
    public JavaServer () {                                                   
        // Our handler is a regular Java object. It can have a               
        // constructor and member variables in the ordinary fashion.         
        // Public methods will be exposed to XML-RPC clients.                
    }                                                                        
                                                                             
    public Hashtable sumAndDifference (int x, int y) {                       
        Hashtable result = new Hashtable();                                  
        result.put("sum", new Integer(x + y));                               
        result.put("difference", new Integer(x - y));                        
        return result;                                                       
    }                                                                        
                                                                             
    public static void main (String [] args) {                               
        try {                                                                
                                                                             
            // Invoke me as <http://localhost:8080/RPC2>.                    
            WebServer server = new WebServer(8080);                          
            server.addHandler("sample", new JavaServer());                   
                                                                             
        } catch (Exception exception) {                                      
            System.err.println("JavaServer: " + exception.toString());       
        }                                                                    
    }                                                                        
}                                                                            
-----------------------------------------------------------------------------

10. Using XML-RPC with PHP

Edd Dumbill has implemented XML-RPC for PHP. You can download it from the 
UsefulInc XML-RPC website.

To install the distribution, decompress it and copy xmlrpc.inc and
xmlrpcs.inc into the same directory as your PHP scripts.
-----------------------------------------------------------------------------

10.1. A PHP Client

The following script shows how to embed XML-RPC calls into a web page.
<html>                                                                       
<head>                                                                       
<title>XML-RPC PHP Demo</title>                                              
</head>                                                                      
<body>                                                                       
<h1>XML-RPC PHP Demo</h1>                                                    
                                                                             
<?php                                                                        
include 'xmlrpc.inc';                                                        
                                                                             
// Make an object to represent our server.                                   
$server = new xmlrpc_client('/api/sample.php',                               
                            'xmlrpc-c.sourceforge.net', 80);                 
                                                                             
// Send a message to the server.                                             
$message = new xmlrpcmsg('sample.sumAndDifference',                          
                         array(new xmlrpcval(5, 'int'),                      
                               new xmlrpcval(3, 'int')));                    
$result = $server->send($message);                                           
                                                                             
// Process the response.                                                     
if (!$result) {                                                              
    print "<p>Could not connect to HTTP server.</p>";                        
} elseif ($result->faultCode()) {                                            
    print "<p>XML-RPC Fault #" . $result->faultCode() . ": " .               
        $result->faultString();                                              
} else {                                                                     
    $struct = $result->value();                                              
    $sumval = $struct->structmem('sum');                                     
    $sum = $sumval->scalarval();                                             
    $differenceval = $struct->structmem('difference');                       
    $difference = $differenceval->scalarval();                               
    print "<p>Sum: " . htmlentities($sum) .                                  
        ", Difference: " . htmlentities($difference) . "</p>";               
}                                                                            
?>                                                                           
                                                                             
</body></html>                                                               

If your webserver doesn't run PHP scripts, see the [http://www.php.net/] PHP
website for more information.
-----------------------------------------------------------------------------

10.2. A PHP Server

The following script shows how to implement an XML-RPC server using PHP.
<?php                                                                        
include 'xmlrpc.inc';                                                        
include 'xmlrpcs.inc';                                                       
                                                                             
function sumAndDifference ($params) {                                        
                                                                             
    // Parse our parameters.                                                 
    $xval = $params->getParam(0);                                            
    $x = $xval->scalarval();                                                 
    $yval = $params->getParam(1);                                            
    $y = $yval->scalarval();                                                 
                                                                             
    // Build our response.                                                   
    $struct = array('sum' => new xmlrpcval($x + $y, 'int'),                  
                    'difference' => new xmlrpcval($x - $y, 'int'));          
    return new xmlrpcresp(new xmlrpcval($struct, 'struct'));                 
}                                                                            
                                                                             
// Declare our signature and provide some documentation.                     
// (The PHP server supports remote introspection. Nifty!)                    
$sumAndDifference_sig = array(array('struct', 'int', 'int'));                
$sumAndDifference_doc = 'Add and subtract two numbers';                      
                                                                             
new xmlrpc_server(array('sample.sumAndDifference' =>                         
                        array('function' => 'sumAndDifference',              
                              'signature' => $sumAndDifference_sig,          
                              'docstring' => $sumAndDifference_doc)));       
?>                                                                           

You would normally invoke this as something like http://localhost/path/
sumAndDifference.php.
-----------------------------------------------------------------------------

11. Using XML-RPC with Microsoft .NET

Charles Cook is writing an excellent new chapter for this HOWTO. You can find
a draft online. If that page disappears, look for a new version of the
XML-RPC HOWTO at the Linux Documentation Project.
-----------------------------------------------------------------------------

12. Using XML-RPC with Ruby

(This section of the XML-RPC HOWTO was generously provided by Michael
Neumann.)

[http://www.ruby-lang.org/] Ruby is an object-oriented scripting language. It
already has a major following in Japan, and it's becoming popular elsewhere.

To use XML-RPC with Ruby, you must first install Yoshida Masato's xmlparser
module (a wrapper for James Clark's expat parser). This can be found at the 
Ruby Application Archive.

Then, you must install [http://www.s-direktnet.de/homepages/neumann/xmlrpc4r/
index.html] xmlrpc4r using the following commands:
bash$ tar -xvzf xmlrpc4r-1_2.tar.gz                                          
bash$ cd xmlrpc4r-1_2                                                        
bash$ su root -c "ruby install.rb"                                           
-----------------------------------------------------------------------------

12.1. A Ruby Client

Here's a simple Ruby client:
require "xmlrpc/client"                                                      
                                                                             
# Make an object to represent the XML-RPC server.                            
server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")  
                                                                             
# Call the remote server and get our result                                  
result = server.call("sample.sumAndDifference", 5, 3)                        
                                                                             
sum = result["sum"]                                                          
difference = result["difference"]                                            
                                                                             
puts "Sum: #{sum}, Difference: #{difference}"                                
-----------------------------------------------------------------------------

12.2. A Ruby Server

Here's a simple Ruby server:
require "xmlrpc/server"                                                      
                                                                             
s = XMLRPC::CGIServer.new                                                    
                                                                             
s.add_hanlder("sample.sumAndDifference") do |a,b|                            
  { "sum" => a + b, "difference" => a - b }                                  
end                                                                          
                                                                             
s.serve                                                                      

This could also have been written as follows:
require "xmlrpc/server"                                                      
                                                                             
s = XMLRPC::CGIServer.new                                                    
                                                                             
class MyHandler                                                              
  def sumAndDifference(a, b)                                                 
    { "sum" => a + b, "difference" => a - b }                                
  end                                                                        
end                                                                          
                                                                             
s.add_handler("sample", MyHandler.new)                                       
s.serve                                                                      

To run either server in standalone mode, replace the second line of code with
the following:
s = XMLRPC::Server.new(8080)                                                 
-----------------------------------------------------------------------------

13. Using XML-RPC with Proprietary Languages

Implementations of XML-RPC are available for the following proprietary
programming languages and environments.
-----------------------------------------------------------------------------

13.1. Using XML-RPC with K

(This section of the XML-RPC HOWTO was generously provided by Christian
Langreiter.)

[http://www.kx.com/] K is a language used in finance and database
development. To install XML-RPC for K, download it from the Kx website.
Uncompress and copy the files into the directory in which you keep your .k
programs.

Here's a short client:
\l kxr                                                                       
server:("localhost";"/cgi-bin/sumAndDifference.cgi");                        
.kxr.c[server;"sumAndDifference";2 3]                                        

And here's a server:
\l kxrsc                                                                     
.kxr.sm: ,("sumAndDifference";{.((`sum;+/x);(`difference;-/x))})             

More examples are included in the distribution.
-----------------------------------------------------------------------------

14. Applications with Built-in XML-RPC Support

Several popular Linux applications include support for XML-RPC. These have
already been described elsewhere, so we mostly provide pointers to articles.
-----------------------------------------------------------------------------

14.1. Zope

Articles on using XML-RPC with Zope are available elsewhere on the web:

  * XML-RPC Programming with Zope by Jon Udell
   
  * Zope XML-RPC at UserLand.Com
   

-----------------------------------------------------------------------------
14.2. KDE 2.0

KDE 2.0 includes Kurt Ganroth's kxmlrpc daemon, which allows you to script
KDE applications using XML-RPC.

Here's a short sample application in Python. It shows you how to connect to
kxmlrpc, manipulate your KDE address book, and query the KDE trader.

If you have any other articles or example code, please see Section 15.3. We'd
like to have more information on scripting KDE.
-----------------------------------------------------------------------------

15. About This Document

This document is part of the Linux Documentation Project. Thanks go to Dave
Winer and maintainers of all the various XML-RPC libraries.
-----------------------------------------------------------------------------

15.1. New Versions of This Document

New versions of this document are available at the Linux Documentation
Project website.

They also provide this manual in alternate formats, including [http://
www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/pdf/XML-RPC-HOWTO.pdf]
PDF, gzipped HTML and ASCII text.
-----------------------------------------------------------------------------

15.2. Contributors to the XML-RPC HOWTO

The section on Ruby was contributed by Michael Neumann (neumann AT
s-direktnet DOT de). The section on K was contributed by Christian Langreiter
(c DOT langreiter AT synerge DOT at).

These contributors are all credited at the beginning of their sections.
-----------------------------------------------------------------------------

15.3. Submitting Other Snippets

If you have a sample client or server in another language or environment,
we'd love to include it in this manual. To add a new entry, we need the
following information:

  * The URL of the XML-RPC implementation used.
   
  * Installation instructions.
   
  * A complete, runnable program.
   
  * Compilation instructions, if applicable.
   

E-mail your example to the xmlrpc-c-devel mailing list or directly to
[mailto:eric.kidd@pobox.com] Eric Kidd.

Thank you for your help!
