LDP/LDP/howto/docbook/XML-RPC-HOWTO.xml

1579 lines
53 KiB
XML

<?xml version="1.0"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
<!ENTITY license "
<para>Permission is granted to copy, distribute and/or modify this
document under the terms of the <ulink type='http'
url='http://www.fsf.org/copyleft/fdl.html'><citetitle>GNU Free
Documentation License</citetitle></ulink>, 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 <citetitle>GNU Free Documentation
License</citetitle> from the Free Software Foundation by visiting
<ulink type='http' url='http://www.fsf.org/'>their Web site</ulink>
or by writing to: Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA.</para>
<para>This manual contains short example programs (<quote>the
Software</quote>). 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:</para>
<para>THE SOFTWARE IS PROVIDED <quote>AS IS</quote>, 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.</para>
">
<!ENTITY % GoodStyleSheets "IGNORE">
<!--
<![%GoodStyleSheets;[
<!ENTITY legal.notice "
<legalnotice id='xmlrpc-howto-legal'>&license;</legalnotice>
">
<!ENTITY legal.section "">
]]>
-->
<!ENTITY legal.notice "">
<!ENTITY legal.section "
<section id='xmlrpc-howto-legal'>
<title>Legal Notice</title>
&license;
</section>
">
]>
<article id="xmlrpc-howto">
<title>XML-RPC HOWTO</title>
<articleinfo>
<title>XML-RPC HOWTO</title>
<pubdate>0.8.0, 2001-04-12</pubdate>
<editor>
<firstname>Eric</firstname>
<surname>Kidd</surname>
</editor>
<authorgroup>
<author>
<firstname>Eric</firstname>
<surname>Kidd</surname>
<affiliation>
<orgname>Source Builders</orgname>
<address><email>eric.kidd@pobox.com</email></address>
</affiliation>
</author>
<author>
<firstname>Charles</firstname>
<surname>Cook</surname>
<affiliation>
<orgname>Cook Computing</orgname>
<address><email>charlescook@ukonline.co.uk</email></address>
</affiliation>
</author>
<author>
<othername>And Other Contributors</othername>
</author>
</authorgroup>
<copyright>
<year>2001</year>
<holder>Eric Kidd</holder>
<holder>Charles Cook</holder>
</copyright>
<abstract>
<para>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, XML-RPC.Net and other languages. Includes sections on
Zope and KDE 2.0. Applies to all operating systems with XML-RPC
support.</para>
</abstract>
&legal.notice;
<revhistory id="revhistory">
<revision>
<revnumber>0.9.0</revnumber>
<date>2001-05-13</date>
<revremark>Merged in Charles Cook's chapter on
XML-RPC.Net.</revremark>
</revision>
<revision>
<revnumber>0.8.0</revnumber>
<date>2001-04-12</date>
<revremark>Updated section on common interfaces. Added pointer to
XML-RPC.Net information.</revremark>
</revision>
<revision>
<revnumber>0.7.0</revnumber>
<date>2001-04-03</date>
<revremark>Added section on C++ proxy classes.</revremark>
</revision>
<revision>
<revnumber>0.6.0</revnumber>
<date>2001-02-02</date>
<revremark>Added sections on Ruby, K and common
interfaces.</revremark>
</revision>
<revision>
<revnumber>0.5.0</revnumber>
<date>2001-01-23</date>
<revremark>Initial version.</revremark>
</revision>
</revhistory>
</articleinfo>
&legal.section;
<section id="xmlrpc-howto-intro">
<title>What is XML-RPC?</title>
<para><ulink url="http://www.xmlrpc.com/">XML-RPC</ulink> 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.</para>
<para>Here's a short XML-RPC client written in Perl. (We use Ken
MacLeod's <ulink
url="http://bitsko.slc.ut.us/~ken/xml-rpc/">Frontier::Client</ulink>
module.)</para>
<programlisting format="linespecific">use Frontier::Client;
$server = Frontier::Client->new(url => 'http://betty.userland.com/RPC2');
$name = $server->call('examples.getStateName', 41);
print "$name\n";</programlisting>
<para>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.)</para>
<para>Here's the same program in Python. (This time, we use Fredrik
Lundh's <ulink
url="http://www.pythonware.com/products/xmlrpc/">xmlrpclib</ulink>.)</para>
<programlisting format="linespecific">python> import xmlrpclib
python> server = xmlrpclib.Server("http://betty.userland.com/RPC2")
python> server.examples.getStateName(41)
'South Dakota'</programlisting>
<para>In the following chapters, you'll learn how to write XML-RPC
clients and servers in a variety of programming languages.</para>
<section id="xmlrpc-howto-spec">
<title>How it Works</title>
<para>XML-RPC is described fully in Dave Winer's <ulink
url="http://www.xmlrpc.com/spec">official specification</ulink>. If
you're curious, go ahead and take a look&mdash;it's a quick and
straight-forward read.</para>
<para>On the wire, XML-RPC values are encoded as XML:</para>
<programlisting>&lt;methodCall>
&lt;methodName>sample.sumAndDifference&lt;/methodName>
&lt;params>
&lt;param>&lt;value>&lt;int>5&lt;/int>&lt;/value>&lt;/param>
&lt;param>&lt;value>&lt;int>3&lt;/int>&lt;/value>&lt;/param>
&lt;/params>
&lt;/methodCall></programlisting>
<para>This is verbose, but compresses readily. It's also faster than
you might expect&mdash;according to measurements by Rick Blair, a
round-trip XML-RPC call takes 3 milliseconds using Hannes
Walln&ouml;fer's Java implementation.</para>
</section>
<section id="xmlrpc-howto-types">
<title>Supported Data Types</title>
<para>XML-RPC supports the following data types:</para>
<variablelist>
<varlistentry>
<term><literal>int</literal></term>
<listitem>
<para>A signed, 32-bit integer.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>string</literal></term>
<listitem>
<para>An ASCII string, which may contain NULL bytes. (Actually,
several XML-RPC implementations support Unicode, thanks to the
underlying features of XML.)</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>boolean</literal></term>
<listitem>
<para>Either true or false.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>double</literal></term>
<listitem>
<para>A double-precision floating point number. (Accuracy may
be limited in some implementations.)</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>dateTime.iso8601</literal></term>
<listitem>
<para>A date and time. Unfortunately, since XML-RPC forbids the
use of timezones, this is very nearly useless.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>base64</literal></term>
<listitem>
<para>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.)</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>array</literal></term>
<listitem>
<para>An one-dimensional array of values. Individual values may
be of any type.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>struct</literal></term>
<listitem>
<para>A collection of key-value pairs. The keys are strings;
the values may be of any type.</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="xmlrpc-howto-history">
<title>The History of XML-RPC</title>
<para>XML-RPC was inspired by two earlier protocols. The first is an
anonymous RPC protocol designed by Dave Winer and announced in an
<ulink
url="http://davenet.userland.com/1998/02/27/rpcOverHttpViaXml">old
DaveNet essay</ulink>. (This is why XML-RPC servers are often
installed under <filename>/RPC2</filename>.) The other, more
important inspiration was an early draft of the SOAP protocol.</para>
<para>A longer <ulink
url="http://www.xmlrpc.com/stories/storyReader$555">history of
XML-RPC</ulink> has been generously provided by Dave Winer. This also
explains the relationship between XML-RPC and SOAP.</para>
</section>
</section>
<section id="xmlrpc-howto-competition">
<title>XML-RPC vs. Other Protocols</title>
<para>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.</para>
<para>The opinions in the section are obviously biased; please take
them with a grain of salt.</para>
<section id="xmlrpc-howto-corba">
<title>XML-RPC vs. CORBA</title>
<para><ulink url="http://www.corba.org/">CORBA</ulink> 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 <ulink
url="http://www.gnome.org/">Gnome</ulink> project for
interapplication communication.</para>
<para>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
<glossterm>interface definition language</glossterm> (IDL), allowing
you to define readable, object-oriented APIs.</para>
<para>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.</para>
</section>
<section id="xmlrpc-howto-dcom">
<title>XML-RPC vs. DCOM</title>
<para><ulink
url="http://www.microsoft.com/com/tech/DCOM.asp">DCOM</ulink> 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.</para>
</section>
<section id="xmlrpc-howto-soap">
<title>XML-RPC vs. SOAP</title>
<para><ulink url="http://www.w3.org/TR/SOAP/">SOAP</ulink> 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.</para>
<para>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.</para>
<para>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.</para>
<para>Basically, if you like XML-RPC, but wish the protocol had more
features, check out SOAP. :-)</para>
</section>
</section>
<section id="xmlrpc-howto-interfaces">
<title>Common XML-RPC Interfaces</title>
<para>Several XML-RPC servers provide built-in methods. These aren't
part of XML-RPC itself, but they make handy add-ons.</para>
<section id="xmlrpc-howto-api-introspection">
<title>Introspection: Discovering Server APIs</title>
<para>Edd Dumbill <ulink
url="http://xmlrpc.usefulinc.com/doc/reserved.html">proposed</ulink>
the following set of methods:</para>
<synopsis><returnvalue>array</returnvalue> <function>system.listMethods</function> ()
<returnvalue>string</returnvalue> <function>system.methodHelp</function> (<type>string</type> <parameter>methodName</parameter>)
<returnvalue>array</returnvalue> <function>system.methodSignature</function> (<type>string</type> <parameter>methodName</parameter>)</synopsis>
<para>If a server supports these methods, you can ask it to print out
some documentation:</para>
<programlisting>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</programlisting>
<para>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 <ulink
url="http://xmlrpc-c.sourceforge.net/hacks.php">XML-RPC
Hacks</ulink> page. Please feel free to add introspection support to
other XML-RPC servers!</para>
<para>Various client-side tools (documentation generators, wrapper
generators, and so on) can be found at the XML-RPC Hacks page as
well.</para>
</section>
<section id="xmlrpc-howto-api-boxcarring">
<title>Boxcarring: Sending Multiple Requests at Once</title>
<para>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:</para>
<synopsis><returnvalue>array</returnvalue> <function>system.multicall</function> (<type>array</type> <parameter>calls</parameter>)</synopsis>
<para>You can find more information in the <ulink
url="http://www.xmlrpc.com/discuss/msgReader$1208">system.multicall
RFC</ulink>.</para>
<para>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 <ulink
url="http://xmlrpc-c.sourceforge.net/hacks.php">XML-RPC
Hacks</ulink> page.</para>
</section>
</section>
<section id="xmlrpc-howto-api">
<title>A Sample API: <function>sumAndDifference</function></title>
<para>To demonstrate XML-RPC, we implement the following API in as many
languages as possible.</para>
<synopsis><returnvalue>struct</returnvalue> <function>sample.sumAndDifference</function> (<type>int</type> <parameter>x</parameter>, <type>int</type> <parameter>y</parameter>)</synopsis>
<para>This function takes two integers as arguments, and returns an
XML-RPC <literal>&lt;struct></literal> containing two elements:</para>
<variablelist>
<varlistentry>
<term><parameter>sum</parameter></term>
<listitem>
<para>The sum of the two integers.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>difference</parameter></term>
<listitem>
<para>The difference between the two integers.</para>
</listitem>
</varlistentry>
</variablelist>
<para>It's not very useful, but it makes a nice example. :-)</para>
<para>This function (and others) are available using the URL
<literal>http://xmlrpc-c.sourceforge.net/api/sample.php</literal>.
(This URL won't do anything in a browser; it requires an XML-RPC
client.)</para>
</section>
<section id="xmlrpc-howto-perl">
<title>Using XML-RPC with Perl</title>
<para>Ken MacLeod has implemented XML-RPC for Perl. You can find his
Frontier::RPC module at his <ulink
url="http://bitsko.slc.ut.us/~ken/xml-rpc/">website</ulink> or through
<ulink url="http://www.cpan.org/">CPAN</ulink>.</para>
<para>To install Frontier::RPC, download the package and compile
it in the standard fashion:</para>
<programlisting>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'</programlisting>
<para>(The process will be slightly different on Windows systems, or if
you don't have root access. Consult your Perl documentation for
details.)</para>
<section id="xmlrpc-howto-perl-client">
<title>A Perl Client</title>
<para>The following program shows how to call an XML-RPC server from
Perl:</para>
<programlisting>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";</programlisting>
</section>
<section id="xmlrpc-howto-perl-server">
<title>A Stand-Alone Perl Server</title>
<para>The following program shows how to write an XML-RPC server in
Perl:</para>
<programlisting>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' => \&amp;sumAndDifference};
Frontier::Daemon->new(LocalPort => 8080, methods => $methods)
or die "Couldn't start HTTP server: $!";</programlisting>
</section>
<section id="xmlrpc-howto-perl-cgi">
<title>A CGI-Based Perl Server</title>
<para><literal>Frontier::RPC2</literal> doesn't provide built-in
support for CGI-based servers. It <emphasis>does</emphasis>, however,
provide most of the pieces you'll need.</para>
<para>Save the following code as
<filename>sumAndDifference.cgi</filename> in your web server's
<filename>cgi-bin</filename> directory. (On Unix systems, you'll need
to make it executable by typing <literal>chmod +x
sumAndDifference.cgi</literal>.)</para>
<programlisting>#!/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' => \&amp;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 &lt;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 &lt;&lt;"EOD";
Status: $code $message
Content-type: text/html
&lt;title>$code $message&lt;/title>
&lt;h1>$code $message&lt;/h1>
&lt;p>Unexpected error processing XML-RPC request.&lt;/p>
EOD
exit 0;
}
# Send an XML document (but don't exit).
sub send_xml ($) {
my ($xml_string) = @_;
my $length = length($xml_string);
print &lt;&lt;"EOD";
Status: 200 OK
Content-type: text/xml
Content-length: $length
EOD
# We want precise control over whitespace here.
print $xml_string;
}</programlisting>
<para>You can copy the utility routines into your own CGI
scripts.</para>
</section>
</section>
<section id="xmlrpc-howto-python">
<title>Using XML-RPC with Python</title>
<para>Fredrik Lundh has provided an excellent <ulink
url="http://www.pythonware.com/products/xmlrpc/">XML-RPC library for
Python</ulink>.</para>
<para>To install, download the latest version. You can either stick the
<filename>*.py</filename> files in the same directory as your Python
code, or you can install them in your system's Python directory.</para>
<para>RedHat 6.2 users can type the following:</para>
<programlisting>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> <keycap>Control-D</keycap>
bash$ su -c 'cp *.py *.pyc /usr/lib/python1.5/'</programlisting>
<para>We <literal>import</literal> two of the <filename>*.py</filename>
files to trick Python into compiling them. Users of other platforms
should consult their Python documentation.</para>
<para>For more Python examples, see the article <ulink
url="http://www.oreillynet.com/pub/a/python/2001/01/17/xmlrpcserver.html">XML-RPC:
It Works Both Ways</ulink> on the O'Reilly Network.</para>
<section id="xmlrpc-howto-python-client">
<title>A Python Client</title>
<para>The following program shows how to call an XML-RPC server from
Python:</para>
<programlisting>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']</programlisting>
</section>
</section>
<section id="xmlrpc-howto-c">
<title>Using XML-RPC with C and C++</title>
<para>To get a copy of XML-RPC for C/C++, see the <ulink
url="http://xmlrpc-c.sourceforge.net">xmlrpc-c website</ulink>.</para>
<para>You can either download everything in RPM format, or you can
build it from source.</para>
<section id="xmlrpc-howto-c-client">
<title>A C Client</title>
<para>Save the following code in a file called
<filename>getSumAndDifference.c</filename>:</para>
<programlisting>#include &lt;stdio.h>
#include &lt;xmlrpc.h>
#include &lt;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(&amp;env);
/* Call our XML-RPC server. */
result = xmlrpc_client_call(&amp;env, SERVER_URL,
"sample.sumAndDifference", "(ii)",
(xmlrpc_int32) 5,
(xmlrpc_int32) 3);
die_if_fault_occurred(&amp;env);
/* Parse our result value. */
xmlrpc_parse_value(&amp;env, result, "{s:i,s:i,*}",
"sum", &amp;sum,
"difference", &amp;difference);
die_if_fault_occurred(&amp;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(&amp;env);
xmlrpc_client_cleanup();
return 0;
}</programlisting>
<para>To compile it, you can type:</para>
<programlisting>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</programlisting>
<para>You may need to replace <command>gcc</command> with the name of
your system's C compiler.</para>
</section>
<section id="xmlrpc-howto-cc-client">
<title>A C++ Client</title>
<para>Save the following code in a file called
<filename>getSumAndDifference2.cc</filename>:</para>
<programlisting>#include &lt;iostream.h>
#include &lt;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 &lt;&lt; "Sum: " &lt;&lt; sum &lt;&lt; ", Difference: " &lt;&lt; diff &lt;&lt; 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&amp; fault) {
cerr &lt;&lt; argv[0] &lt;&lt; ": XML-RPC fault #" &lt;&lt; fault.getFaultCode()
&lt;&lt; ": " &lt;&lt; fault.getFaultString() &lt;&lt; endl;
XmlRpcClient::Terminate();
exit(1);
}
// Shut down our client library.
XmlRpcClient::Terminate();
return 0;
}</programlisting>
<para>To compile it, you can type:</para>
<programlisting>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</programlisting>
<para>You'll need a reasonably modern C++ compiler for this to
work.</para>
</section>
<section id="xmlrpc-howto-cc-proxy">
<title>A C++ Client with Proxy Classes</title>
<para>If your XML-RPC server supports the <link
linkend="xmlrpc-howto-api-introspection">Introspection API</link>,
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:</para>
<programlisting>bash$ xml-rpc-api2cpp \
> http://xmlrpc-c.sourceforge.net/api/sample.php sample SampleProxy</programlisting>
<para>This will generate a proxy class named
<literal>SampleProxy</literal> containing wrappers for all the
methods beginning with <literal>sample</literal>. You can edit this
class in any fashion you'd like.</para>
</section>
<section id="xmlrpc-howto-c-cgi">
<title>A CGI-Based C Server</title>
<para>Save the following code in a file called
<filename>sumAndDifference.c</filename>:</para>
<programlisting>#include &lt;xmlrpc.h>
#include &lt;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)", &amp;x, &amp;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",
&amp;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();
}</programlisting>
<para>To compile it, you can type:</para>
<programlisting>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</programlisting>
<para>Once this is done, copy
<filename>sumAndDifference.cgi</filename> into your webserver's
<filename>cgi-bin</filename> directory.</para>
</section>
</section>
<section id="xmlrpc-howto-java">
<title>Using XML-RPC with Java</title>
<para>Hannes Walln&ouml;fer has provided <ulink
url="http://helma.at/hannes/xmlrpc/">an excellent
implementation</ulink> of XML-RPC for Java.</para>
<para>To install it, download the distribution, unzip it, and add the
<filename>*.jar</filename> files to your <envar>CLASSPATH</envar>. On a
Unix system, you can do this by typing:</para>
<programlisting>bash$ unzip xmlrpc-java.zip
bash$ cd xmlrpc-java/lib
bash$ CLASSPATH=`pwd`/openxml-1.2.jar:`pwd`/xmlrpc.jar:$CLASSPATH</programlisting>
<section id="xmlrpc-howto-java-client">
<title>A Java Client</title>
<para>Save the following program in a file named
<filename>JavaClient.java</filename>.</para>
<programlisting>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());
}
}
}</programlisting>
</section>
<section id="xmlrpc-howto-java-server">
<title>A Stand-Alone Java Server</title>
<para>Save the following program in a file named
<filename>JavaServer.java</filename>.</para>
<programlisting>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 &lt;http://localhost:8080/RPC2>.
WebServer server = new WebServer(8080);
server.addHandler("sample", new JavaServer());
} catch (Exception exception) {
System.err.println("JavaServer: " + exception.toString());
}
}
}</programlisting>
</section>
</section>
<section id="xmlrpc-howto-php">
<title>Using XML-RPC with PHP</title>
<para>Edd Dumbill has implemented XML-RPC for PHP. You can download it
from the <ulink url="http://xmlrpc.usefulinc.com/">UsefulInc XML-RPC
website</ulink>.</para>
<para>To install the distribution, decompress it and copy
<filename>xmlrpc.inc</filename> and <filename>xmlrpcs.inc</filename>
into the same directory as your PHP scripts.</para>
<section id="xmlrpc-howto-php-client">
<title>A PHP Client</title>
<para>The following script shows how to embed XML-RPC calls into a
web page.</para>
<programlisting>&lt;html>
&lt;head>
&lt;title>XML-RPC PHP Demo&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>XML-RPC PHP Demo&lt;/h1>
&lt;?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 "&lt;p>Could not connect to HTTP server.&lt;/p>";
} elseif ($result->faultCode()) {
print "&lt;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 "&lt;p>Sum: " . htmlentities($sum) .
", Difference: " . htmlentities($difference) . "&lt;/p>";
}
?>
&lt;/body>&lt;/html></programlisting>
<para>If your webserver doesn't run PHP scripts, see the <ulink
url="http://www.php.net/">PHP website</ulink> for more
information.</para>
</section>
<section id="xmlrpc-howto-php-server">
<title>A PHP Server</title>
<para>The following script shows how to implement an XML-RPC server
using PHP.</para>
<programlisting>&lt;?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)));
?></programlisting>
<para>You would normally invoke this as something like
<literal>http://localhost/path/sumAndDifference.php</literal>.</para>
</section>
</section>
<section id="xmlrpc-howto-dotnet">
<title>Using XML-RPC with Microsoft .NET</title>
<para><emphasis>(This section of the XML-RPC HOWTO was generously
provided by Charles Cook.)</emphasis></para>
<para>Charles Cook has implemented XML-RPC for Microsoft's .NET
environment. You can find his XML-RPC.Net library at <ulink
url="http://www.cookcomputing.com/xmlrpc/xmlrpc.shtml">the Cook
Computing website</ulink>.</para>
<para>The following code requires the .NET SDK to be installed. To
build and run XML-RPC.Net client and server applications, unzip
<filename>cookcomputing.xmlrpc.dll</filename> from the XML-RPC.Net
distribution and copy to the required directories.</para>
<para>XML-RPC.Net is compliant with the Common Language Specification
and so can be used to build XML-RPC clients and servers using any
CLS-compliant programming language. At the time of writing this means
the languages provided by Microsoft&mdash;C#, VB.Net, JScript, and
Managed C++&mdash;but in the future will include other languages such
as Eiffel, Perl and Python.</para>
<para><function>sample.sumAndDifference</function> client and server
samples are presented here in both C# and VB.Net. The client samples
make synchronous calls but it is also possible to make asynchronous
calls&mdash;refer to the XML-RPC.Net documentation for further
information.</para>
<!-- The following text points to a non-existant web page, and will be
merged in when the link works: Publicly available demo Services
including the sample Services presented below, are listed at:
http://www.cookcomputing.com/dotxmlrpcdemos.html -->
<section id="xmlrpc-howto-csharp-client">
<title>A C# Client</title>
<para>Save the following code in a file called
<filename>getSumAndDiffCS.cs</filename>:</para>
<programlisting>using System;
using CookComputing.XmlRpc;
public struct Result
{
public int sum;
public int difference;
}
[XmlRpcUri(
"http://aspx.securedomains.com/cookcomputing/sumanddiffvb.aspx")]
class Proxy : XmlRpcClientProtocol
{
[XmlRpcMethod("sample.sumAndDifference")]
public Result SumAndDifference(int x, int y)
{
return (Result)Invoke("SumAndDifference", new Object[]{x,y})[0];
}
}
public class App
{
public static int Main(string[] args)
{
try
{
Proxy theProxy = new Proxy();
Result ret = theProxy.SumAndDifference(5, 3);
Console.WriteLine("5 + 3 = {0}", ret.sum);
Console.WriteLine("5 - 3 = {0}", ret.difference);
}
catch(XmlRpcClientException cex)
{
Console.WriteLine("Client exception: {0} {1}",
cex.FaultCode, cex.FaultString);
}
catch(XmlRpcFaultException fex)
{
Console.WriteLine("Server exception: {0} {1}",
fex.FaultCode, fex.FaultString);
}
return 0;
}
}</programlisting>
<para>Use the following command to build the client:</para>
<programlisting>csc /r:cookcomputing.xmlrpc.dll getSumAndDiffCS.cs</programlisting>
</section>
<section id="xmlrpc-howto-vbdotnet-client">
<title>A Visual Basic .NET Client</title>
<para>Save the following code in a file called
<filename>getSumAndDiffVB.vb</filename>:</para>
<programlisting>Imports CookComputing.XmlRpc
Module Module1
Structure Result
Dim sum, difference As Integer
End Structure
Class &lt;XmlRpcUri( _
"http://aspx.securedomains.com/cookcomputing/sumanddiffcs.xmlrpc")> _
Proxy : Inherits XmlRpcClientProtocol
Public Function &lt;XmlRpcMethod("sample.sumAndDifference")> _
SumAndDifference(ByVal x As Integer, ByVal y As Integer) As Result
Dim results As Object() = Me.Invoke("SumAndDifference", _
New Object() {x,y})
Return CType(results(0), Result)
End Function
End Class
Sub Main()
Dim theProxy As New Proxy()
Try
Dim ret As Result = theProxy.SumAndDifference(5, 3)
Console.WriteLine("5 + 3 = {0}", ret.sum)
Console.WriteLine("5 - 3 = {0}", ret.difference)
Catch cex As XmlRpcClientException
Console.WriteLine("Client exception: {0} {1}", _
cex.FaultCode, cex.FaultString)
Catch fex As XmlRpcFaultException
Console.WriteLine("Server exception: {0} {1}", _
fex.FaultCode, fex.FaultString)
End Try
End Sub
End Module</programlisting>
<para>Use the following command to build the client:</para>
<programlisting>vbc /r:cookcomputing.xmlrpc.dll getSumAndDiffVB.vb</programlisting>
</section>
<section id="xmlrpc-howto-csharp-server">
<title>A C# Server</title>
<para>XML-RPC.Net enables the implementation of XML-RPC Services
running in the IIS 5 web server environment.</para>
<para>Save the following code in a file called
<filename>SumAndDiffCS.cs</filename>:</para>
<programlisting>using System;
using CookComputing.XmlRpc;
public struct Result
{
public int sum;
public int difference;
}
[XmlRpcService(Description=
"Sample XML-RPC.Net Service implemented in C#")]
public class SumAndDiffService : XmlRpcService
{
[XmlRpcMethod("sample.sumAndDifference", Description=
"This function takes two integers as arguments and returns an "+
"XML-RPC struct containing two elements: sum, the sum of the "+
"two integers, and difference, the difference between the two "+
"integers")]
public Result SumAndDifference(int x, int y)
{
Result ret;
ret.sum = x + y;
ret.difference = x - y;
return ret;
}
}</programlisting>
<para>Use the following to build the client:</para>
<programlisting>csc /r:System.Web.dll,cookcomputing.xmlrpc.dll /target:library SumAndDiffCS.cs</programlisting>
<para>Create an IIS virtual root, say
<filename>cookcomputing</filename> for this example, and a
<filename>bin</filename> directory underneath it. Place the assembly
(<filename>SumAndDiffCS.dll</filename>) and the XML-RPC.Net assembly
(<filename>cookcomputing.xmlrpc.dll</filename>) in the
<filename>bin</filename> directory.</para>
<para>Create a text file called <filename>config.web</filename> in
the <filename>cookcomputing</filename> root directory with the
following contents:</para>
<programlisting>&lt;configuration>
&lt;httphandlers>
&lt;add verb="*" path="sumanddiffcs.aspx" type="SumAndDiffService,
SumAndDiffCS" />
&lt;/httphandlers>
&lt;/configuration></programlisting>
<para>The Service is now installed and configured. To check this
navigate your browser to the URL of the Service where you will see an
automatically generated documentation page.</para>
</section>
<section id="xmlrpc-howto-vbdotnet-server">
<title>A Visual Basic .NET Server</title>
<para>Save the following code in a file called
<filename>SumAndDiffVB.cs</filename>:</para>
<programlisting>Imports System
Imports CookComputing.XmlRpc
Public Structure Result
Dim sum, difference As Integer
End Structure
Public Class &lt;XmlRpcService(Description:= _
"Sample XML-RPC.Net Service implemented in VB.Net")> _
SumAndDiffService : Inherits XmlRpcService
Public Function &lt;XmlRpcMethod("sample.sumAndDifference", _
Description:= "This function takes two integers as arguments "+ _
"and returns an XML-RPC struct containing two "+ _
"elements: sum, the sum of the two integers, and "+ _
"difference, the difference between the two "+ _
"integers")> _
SumAndDifference(ByVal x As Integer, ByVal y As Integer) As Result
Dim ret As Result
ret.sum = x + y
ret.difference = x - y
Return ret
End Function
End Class</programlisting>
<para>Use the following to build the client:</para>
<programlisting>vbc /r:System.Web.dll,cookcomputing.xmlrpc.dll /target:library SumAndDiffVB.vb</programlisting>
<para>Create an IIS virtual root, say
<filename>cookcomputing</filename> for this example, and a
<filename>bin</filename> directory underneath it. Place the assembly
(<filename>SumAndDiffVB.dll</filename>) and the XML-RPC.Net assembly
(<filename>cookcomputing.xmlrpc.dll</filename>) in the
<filename>bin</filename> directory.</para>
<para>Create a text file called <filename>config.web</filename> in
the <filename>cookcomputing</filename> root directory with the
following contents (note that the entries are case sensitive):</para>
<programlisting>&lt;configuration>
&lt;httphandlers>
&lt;add verb="*" path="sumanddiffvb.aspx" type="SumAndDiffService,
SumAndDiffVB" />
&lt;/httphandlers>
&lt;/configuration></programlisting>
<para>The Service is now installed and configured. To check this
navigate your browser to the URL of the Service where you will see an
automatically generated documentation page.</para>
</section>
</section>
<section id="xmlrpc-howto-ruby">
<title>Using XML-RPC with Ruby</title>
<para><emphasis>(This section of the XML-RPC HOWTO was generously
provided by Michael Neumann.)</emphasis></para>
<para><ulink url="http://www.ruby-lang.org/">Ruby</ulink> is an
object-oriented scripting language. It already has a major following in
Japan, and it's becoming popular elsewhere.</para>
<para>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 <ulink url="http://www.ruby-lang.org/en/raa.html">Ruby
Application Archive</ulink>.</para>
<para>Then, you must install <ulink
url="http://www.s-direktnet.de/homepages/neumann/xmlrpc4r/index.html">xmlrpc4r</ulink>
using the following commands:</para>
<programlisting>bash$ tar -xvzf xmlrpc4r-1_2.tar.gz
bash$ cd xmlrpc4r-1_2
bash$ su root -c "ruby install.rb"</programlisting>
<section id="xmlrpc-howto-ruby-client">
<title>A Ruby Client</title>
<para>Here's a simple Ruby client:</para>
<programlisting>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}"</programlisting>
</section>
<section id="xmlrpc-howto-ruby-server">
<title>A Ruby Server</title>
<para>Here's a simple Ruby server:</para>
<programlisting>require "xmlrpc/server"
s = XMLRPC::CGIServer.new
s.add_hanlder("sample.sumAndDifference") do |a,b|
{ "sum" => a + b, "difference" => a - b }
end
s.serve</programlisting>
<para>This could also have been written as follows:</para>
<programlisting>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</programlisting>
<para>To run either server in standalone mode, replace the second line
of code with the following:</para>
<programlisting>s = XMLRPC::Server.new(8080)</programlisting>
</section>
</section>
<section id="xmlrpc-howto-proprietary">
<title>Using XML-RPC with Proprietary Languages</title>
<para>Implementations of XML-RPC are available for the following
proprietary programming languages and environments.</para>
<section id="xmlrpc-howto-k">
<title>Using XML-RPC with K</title>
<para><emphasis>(This section of the XML-RPC HOWTO was generously
provided by Christian Langreiter.)</emphasis></para>
<para><ulink url="http://www.kx.com/">K</ulink> is a language used in
finance and database development. To install XML-RPC for K, download
it from the <ulink url="http://www.langreiter.com/k/kxr">Kx
website</ulink>. Uncompress and copy the files into the directory in
which you keep your .k programs.</para>
<para>Here's a short client:</para>
<programlisting>\l kxr
server:("localhost";"/cgi-bin/sumAndDifference.cgi");
.kxr.c[server;"sumAndDifference";2 3]</programlisting>
<para>And here's a server:</para>
<programlisting>\l kxrsc
.kxr.sm: ,("sumAndDifference";{.((`sum;+/x);(`difference;-/x))})</programlisting>
<para>More examples are included in the distribution.</para>
</section>
</section>
<section id="xmlrpc-howto-applist">
<title>Applications with Built-in XML-RPC Support</title>
<para>Several popular Linux applications include support for
XML-RPC. These have already been described elsewhere, so we mostly
provide pointers to articles.</para>
<section id="xmlrpc-howto-zope">
<title>Zope</title>
<para>Articles on using XML-RPC with Zope are available elsewhere on
the web:</para>
<itemizedlist>
<listitem>
<para><ulink
url="http://www.byte.com/column/BYT19991021S0014">XML-RPC
Programming with Zope</ulink> by Jon Udell</para>
</listitem>
<listitem>
<para><ulink
url="http://linux.userland.com/stories/storyReader$18">Zope
XML-RPC</ulink> at UserLand.Com</para>
</listitem>
</itemizedlist>
</section>
<section id="xmlrpc-howto-kde">
<title>KDE 2.0</title>
<para>KDE 2.0 includes Kurt Ganroth's <ulink
url="http://kdecvs.stud.fh-heilbronn.de/cvsweb/kdebase/kxmlrpc/">kxmlrpc
daemon</ulink>, which allows you to script KDE applications using
XML-RPC.</para>
<para>Here's a short <ulink
url="http://kdecvs.stud.fh-heilbronn.de/cvsweb/kdebase/kxmlrpc/test/testxmlrpc.py?rev=1.6&amp;content-type=text/x-cvsweb-markup">sample
application</ulink> in Python. It shows you how to connect to
kxmlrpc, manipulate your KDE address book, and query the KDE
trader.</para>
<para>If you have any other articles or example code, please see
<xref linkend="xmlrpc-howto-submitting"/>. We'd like to have more
information on scripting KDE.</para>
</section>
</section>
<section id="xmlrpc-howto-about">
<title>About This Document</title>
<para>This document is part of the <ulink
url="http://www.linuxdoc.org/">Linux Documentation
Project</ulink>. Thanks go to Dave Winer and maintainers of all the
various XML-RPC libraries.</para>
<section id="xmlrpc-howto-versions">
<title>New Versions of This Document</title>
<para>New versions of this document are available at the <ulink
url="http://www.linuxdoc.org/HOWTO/XML-RPC-HOWTO/index.html">Linux
Documentation Project</ulink> website.</para>
<para>They also provide this manual in alternate formats, including
<ulink
url="http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/pdf/XML-RPC-HOWTO.pdf">PDF</ulink>,
<ulink
url="http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/html/XML-RPC-HOWTO-html.tar.gz">gzipped
HTML</ulink> and <ulink
url="http://www.ibiblio.org/pub/Linux/docs/HOWTO/XML-RPC-HOWTO">ASCII
text</ulink>.</para>
</section>
<section id="xmlrpc-howto-contributors">
<title>Contributors to the XML-RPC HOWTO</title>
<para>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).</para>
<para>These contributors are all credited at the beginning of their
sections.</para>
</section>
<section id="xmlrpc-howto-submitting">
<title>Submitting Other Snippets</title>
<para>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:</para>
<itemizedlist>
<listitem>
<para>The URL of the XML-RPC implementation used.</para>
</listitem>
<listitem>
<para>Installation instructions.</para>
</listitem>
<listitem>
<para>A complete, runnable program.</para>
</listitem>
<listitem>
<para>Compilation instructions, if applicable.</para>
</listitem>
</itemizedlist>
<para>E-mail your example to the <ulink
url="http://xmlrpc-c.sourceforge.net/lists.php">xmlrpc-c-devel
mailing list</ulink> or directly to <ulink
url="mailto:eric.kidd@pobox.com">Eric Kidd</ulink>.</para>
<para>Thank you for your help!</para>
</section>
</section>
</article>