LSL Wiki : XMLRPCImplementations

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are c-71-202-89-105.hsd1.ca.comcast.net
Here you'll find some XML-RPC sample implementations in various languages:

Language: Modules/Libraries Used:
ASP aspxmlrpc
C# System.Web
C++ Example 1 XmlRpc++ (Modified)
C++ Example 2 KDE 3.x (Linux)
Java Apache XML-RPC
JavaScript JavaScript O Lait
Perl RPC::XML
PHP Example 1 XML-RPC
PHP Example 2 XML-RPC
Python Example 1 xmlrpclib
Python Example 2 python-xmlrpc
Ruby xmlrpc4r

FYI: XML assumes UTF-8 as the encoding type if not otherwise speficied (like in XML-RPC), in your software you should expect UTF-8 strings when parsing results. SL uses UTF-8 for it's encoding of strings.



ASP


This ASP example uses the aspxmlrpc http://aspxmlrpc.sourceforge.net/ library by David Carter-Tod, et. al..

<%

Dim paramList(0)
Set paramList(0) = CreateObject("Scripting.Dictionary")
paramList(0).Add "Channel","0d58c21c-b56f-57df-745f-9ccd0e06df49"
paramList(0).Add "IntValue",CByte(17)
paramList(0).Add "StringValue","Hello, Alexander!"

Dim myresp
on error resume next
Set myresp = xmlRPC("http://xmlrpc.secondlife.com/cgi-bin/xmlrpc.cgi", "llRemoteData", paramList)
on error goto 0

if err.number <>0 then
	response.write("Error number: " & err.number & "<P>")
	response.write("Error description: " & err.description & "<P>")
else
	response.write("Channel: " & myresp("Channel") & vbCrLf)
	response.write("IntValue: " & myresp("IntValue") & vbCrLf)
	response.write("StringValue: " & myresp("StringValue") & vbCrLf)
end if

%>



C#

C# Implementation by DedricMauriac. Make sure to add a reference to System.Web in your project.

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Web;

/*
 * XmlRpc rpc = new XmlRpc(
 *      new Guid("ba70440d-7d8b-cd1e-db1c-198d563bae55"),
 *      "This is some text",
 *      42);
 * rpc.llRemoteData();
 * Debug.WriteLine(rpc.channel, "channel");
 * Debug.WriteLine(rpc.stringValue, "string");
 * Debug.WriteLine(rpc.intValue, "int");
 */

public class XmlRpc
{
    private const string MethodCallTemplate = @"<?xml version=""1.0""?><methodCall><methodName>llRemoteData</methodName><params><param><value><struct><member><name>Channel</name><value><string>{0}</string></value></member><member><name>IntValue</name><value><int>{1}</int></value></member><member><name>StringValue</name><value><string>{2}</string></value></member></struct></value></param></params></methodCall>";

    public Guid channel;
    public string stringValue;
    public int intValue;
    public bool TimedOut;

    public XmlRpc()
    {
    }
    public XmlRpc(Guid channel, string stringValue, int intValue)
    {
        this.channel = channel;
        this.stringValue = stringValue;
        this.intValue = intValue;
    }

    public void llRemoteData()
    {
        string methodCall = string.Format(MethodCallTemplate, 
            this.channel, 
            this.intValue, 
            HttpUtility.HtmlEncode(this.stringValue)
            );

        Uri requestUri = new Uri("http://xmlrpc.secondlife.com/cgi-bin/xmlrpc.cgi");
        
        string methodResponse = Post(requestUri, methodCall);
        
        ParseResponse(methodResponse);
    }

    private void ParseResponse(string methodResponse)
    {
        if (methodResponse.IndexOf("<fault>") != -1)
        {
            string message = Regex.Match(methodResponse,
                "<value><string>([^>]+)</string></value>")
                .Groups[1].Value;
            throw new ApplicationException(message);
        }

        MatchCollection matches = Regex.Matches(methodResponse, @"<name>([^<]+)</name>\s*<value>\s*<(string|int)>([^<]+)</\2>\s*</value>");
        foreach (Match match in matches)
        {
            string name = match.Groups[1].Value;
            string value = match.Groups[3].Value;
            switch (name)
            {
                case "Channel":
                    this.channel = new Guid(value);
                    break;
                case "StringValue":
                    this.stringValue = HttpUtility.HtmlDecode(value);
                    break;
                case "IntValue":
                    this.intValue = int.Parse(value);
                    break;
            }
        }
    }
    private string Post(Uri requestUri, string data)
    {
        TimedOut = false;
        byte[] postData = ASCIIEncoding.Default.GetBytes(data);
        HttpWebRequest request = null;
        Stream writer = null;
        Stream reader = null;
        WebResponse response = null;
        try
        {
            request = HttpWebRequest.Create(requestUri) as HttpWebRequest;

            request.Method = "POST";
            request.KeepAlive = false;
            request.ContentType = "application/x-www-form-urlencoded";
            request.Timeout = 10000;

            request.ContentLength = postData.Length;

            writer = request.GetRequestStream();
            writer.Write(postData, 0, postData.Length);
            writer.Close();

            response = request.GetResponse();

            reader = response.GetResponseStream();
            byte[] postResponse = new byte[response.ContentLength];
            reader.Read(postResponse, 0, postResponse.Length);

            return ASCIIEncoding.Default.GetString(postResponse);
        }
        catch (WebException ex)
        {
            if (ex.Status == WebExceptionStatus.Timeout)
            {
                TimedOut = true;
                return "";
            }
            else
                throw;
        }
        finally
        {
            if (writer != null)
            {
                writer.Close();
                writer.Dispose();
            }
            if (reader != null)
            {
                reader.Close();
                reader.Dispose();
            }
            if (response != null)
            {
                response.Close();
            }
        }
    }
}



C++


This C++ example uses the XmlRpc++ implementation, with some modifications listed below

Modified XmlRpcValue.cpp (v.07)
#include "XmlRpcValue.h"
#include "XmlRpcException.h"
#include "XmlRpcUtil.h"
#include "base64.h"

#ifndef MAKEDEPEND
# include <iostream>
# include <ostream>
# include <stdlib.h>
# include <stdio.h>
#endif

namespace XmlRpc {


  static const char VALUE_TAG[]     = "<value>";
  static const char VALUE_ETAG[]    = "</value>";

  static const char BOOLEAN_TAG[]   = "<boolean>";
  static const char BOOLEAN_ETAG[]  = "</boolean>";
  static const char DOUBLE_TAG[]    = "<double>";
  static const char DOUBLE_ETAG[]   = "</double>";
  static const char INT_TAG[]       = "<int>";
  static const char I4_TAG[]        = "<int>"; /* Was i4 */
  static const char I4_ETAG[]       = "</int>"; /* Was i4 */
  static const char STRING_TAG[]    = "<string>";
  static const char STRING_ETAG[]   = "</string>";
  static const char DATETIME_TAG[]  = "<dateTime.iso8601>";
  static const char DATETIME_ETAG[] = "</dateTime.iso8601>";
  static const char BASE64_TAG[]    = "<base64>";
  static const char BASE64_ETAG[]   = "</base64>";

  static const char ARRAY_TAG[]     = "<array>";
  static const char DATA_TAG[]      = "<data>";
  static const char DATA_ETAG[]     = "</data>";
  static const char ARRAY_ETAG[]    = "</array>";

  static const char STRUCT_TAG[]    = "<struct>";
  static const char MEMBER_TAG[]    = "<member>";
  static const char NAME_TAG[]      = "<name>";
  static const char NAME_ETAG[]     = "</name>";
  static const char MEMBER_ETAG[]   = "</member>";
  static const char STRUCT_ETAG[]   = "</struct>";


      
  // Format strings
  std::string XmlRpcValue::_doubleFormat("%f");



  // Clean up
  void XmlRpcValue::invalidate()
  {
    switch (_type) {
      case TypeString:    delete _value.asString; break;
      case TypeDateTime:  delete _value.asTime;   break;
      case TypeBase64:    delete _value.asBinary; break;
      case TypeArray:     delete _value.asArray;  break;
      case TypeStruct:    delete _value.asStruct; break;
      default: break;
    }
    _type = TypeInvalid;
    _value.asBinary = 0;
  }

  
  // Type checking
  void XmlRpcValue::assertTypeOrInvalid(Type t)
  {
    if (_type == TypeInvalid)
    {
      _type = t;
      switch (_type) {    // Ensure there is a valid value for the type
        case TypeString:   _value.asString = new std::string(); break;
        case TypeDateTime: _value.asTime = new struct tm();     break;
        case TypeBase64:   _value.asBinary = new BinaryData();  break;
        case TypeArray:    _value.asArray = new ValueArray();   break;
        case TypeStruct:   _value.asStruct = new ValueStruct(); break;
        default:           _value.asBinary = 0; break;
      }
    }
    else if (_type != t)
      throw XmlRpcException("type error");
  }

  void XmlRpcValue::assertArray(int size) const
  {
    if (_type != TypeArray)
      throw XmlRpcException("type error: expected an array");
    else if (int(_value.asArray->size()) < size)
      throw XmlRpcException("range error: array index too large");
  }


  void XmlRpcValue::assertArray(int size)
  {
    if (_type == TypeInvalid) {
      _type = TypeArray;
      _value.asArray = new ValueArray(size);
    } else if (_type == TypeArray) {
      if (int(_value.asArray->size()) < size)
        _value.asArray->resize(size);
    } else
      throw XmlRpcException("type error: expected an array");
  }

  void XmlRpcValue::assertStruct()
  {
    if (_type == TypeInvalid) {
      _type = TypeStruct;
      _value.asStruct = new ValueStruct();
    } else if (_type != TypeStruct)
      throw XmlRpcException("type error: expected a struct");
  }


  // Operators
  XmlRpcValue& XmlRpcValue::operator=(XmlRpcValue const& rhs)
  {
    if (this != &rhs)
    {
      invalidate();
      _type = rhs._type;
      switch (_type) {
        case TypeBoolean:  _value.asBool = rhs._value.asBool; break;
        case TypeInt:      _value.asInt = rhs._value.asInt; break;
        case TypeDouble:   _value.asDouble = rhs._value.asDouble; break;
        case TypeDateTime: _value.asTime = new struct tm(*rhs._value.asTime); break;
        case TypeString:   _value.asString = new std::string(*rhs._value.asString); break;
        case TypeBase64:   _value.asBinary = new BinaryData(*rhs._value.asBinary); break;
        case TypeArray:    _value.asArray = new ValueArray(*rhs._value.asArray); break;
        case TypeStruct:   _value.asStruct = new ValueStruct(*rhs._value.asStruct); break;
        default:           _value.asBinary = 0; break;
      }
    }
    return *this;
  }


  // Predicate for tm equality
  static bool tmEq(struct tm const& t1, struct tm const& t2) {
    return t1.tm_sec == t2.tm_sec && t1.tm_min == t2.tm_min &&
            t1.tm_hour == t2.tm_hour && t1.tm_mday == t1.tm_mday &&
            t1.tm_mon == t2.tm_mon && t1.tm_year == t2.tm_year;
  }

  bool XmlRpcValue::operator==(XmlRpcValue const& other) const
  {
    if (_type != other._type)
      return false;

    switch (_type) {
      case TypeBoolean:  return ( !_value.asBool && !other._value.asBool) ||
                                ( _value.asBool && other._value.asBool);
      case TypeInt:      return _value.asInt == other._value.asInt;
      case TypeDouble:   return _value.asDouble == other._value.asDouble;
      case TypeDateTime: return tmEq(*_value.asTime, *other._value.asTime);
      case TypeString:   return *_value.asString == *other._value.asString;
      case TypeBase64:   return *_value.asBinary == *other._value.asBinary;
      case TypeArray:    return *_value.asArray == *other._value.asArray;

      // The map<>::operator== requires the definition of value< for kcc
      case TypeStruct:   //return *_value.asStruct == *other._value.asStruct;
        {
          if (_value.asStruct->size() != other._value.asStruct->size())
            return false;
          
          ValueStruct::const_iterator it1=_value.asStruct->begin();
          ValueStruct::const_iterator it2=other._value.asStruct->begin();
          while (it1 != _value.asStruct->end()) {
            const XmlRpcValue& v1 = it1->second;
            const XmlRpcValue& v2 = it2->second;
            if ( ! (v1 == v2))
              return false;
            it1++;
            it2++;
          }
          return true;
        }
      default: break;
    }
    return true;    // Both invalid values ...
  }

  bool XmlRpcValue::operator!=(XmlRpcValue const& other) const
  {
    return !(*this == other);
  }


  // Works for strings, binary data, arrays, and structs.
  int XmlRpcValue::size() const
  {
    switch (_type) {
      case TypeString: return int(_value.asString->size());
      case TypeBase64: return int(_value.asBinary->size());
      case TypeArray:  return int(_value.asArray->size());
      case TypeStruct: return int(_value.asStruct->size());
      default: break;
    }

    throw XmlRpcException("type error");
  }

  // Checks for existence of struct member
  bool XmlRpcValue::hasMember(const std::string& name) const
  {
    return _type == TypeStruct && _value.asStruct->find(name) != _value.asStruct->end();
  }

  // Set the value from xml. The chars at *offset into valueXml 
  // should be the start of a <value> tag. Destroys any existing value.
  bool XmlRpcValue::fromXml(std::string const& valueXml, int* offset)
  {
    int savedOffset = *offset;

    invalidate();
    if ( ! XmlRpcUtil::nextTagIs(VALUE_TAG, valueXml, offset))
      return false;       // Not a value, offset not updated

 int afterValueOffset = *offset;
    std::string typeTag = XmlRpcUtil::getNextTag(valueXml, offset);
    bool result = false;
    if (typeTag == BOOLEAN_TAG)
      result = boolFromXml(valueXml, offset);
    else if (typeTag == I4_TAG || typeTag == INT_TAG)
      result = intFromXml(valueXml, offset);
    else if (typeTag == DOUBLE_TAG)
      result = doubleFromXml(valueXml, offset);
    else if (typeTag.empty() || typeTag == STRING_TAG)
      result = stringFromXml(valueXml, offset);
    else if (typeTag == DATETIME_TAG)
      result = timeFromXml(valueXml, offset);
    else if (typeTag == BASE64_TAG)
      result = binaryFromXml(valueXml, offset);
    else if (typeTag == ARRAY_TAG)
      result = arrayFromXml(valueXml, offset);
    else if (typeTag == STRUCT_TAG)
      result = structFromXml(valueXml, offset);
    // Watch for empty/blank strings with no <string>tag
    else if (typeTag == VALUE_ETAG)
    {
      *offset = afterValueOffset;   // back up & try again
      result = stringFromXml(valueXml, offset);
    }

    if (result)  // Skip over the </value> tag
      XmlRpcUtil::findTag(VALUE_ETAG, valueXml, offset);
    else        // Unrecognized tag after <value>
      *offset = savedOffset;

    return result;
  }

  // Encode the Value in xml
  std::string XmlRpcValue::toXml() const
  {
    switch (_type) {
      case TypeBoolean:  return boolToXml();
      case TypeInt:      return intToXml();
      case TypeDouble:   return doubleToXml();
      case TypeString:   return stringToXml();
      case TypeDateTime: return timeToXml();
      case TypeBase64:   return binaryToXml();
      case TypeArray:    return arrayToXml();
      case TypeStruct:   return structToXml();
      default: break;
    }
    return std::string();   // Invalid value
  }


  // Boolean
  bool XmlRpcValue::boolFromXml(std::string const& valueXml, int* offset)
  {
    const char* valueStart = valueXml.c_str() + *offset;
    char* valueEnd;
    long ivalue = strtol(valueStart, &valueEnd, 10);
    if (valueEnd == valueStart || (ivalue != 0 && ivalue != 1))
      return false;

    _type = TypeBoolean;
    _value.asBool = (ivalue == 1);
    *offset += int(valueEnd - valueStart);
    return true;
  }

  std::string XmlRpcValue::boolToXml() const
  {
    std::string xml = VALUE_TAG;
    xml += BOOLEAN_TAG;
    xml += (_value.asBool ? "1" : "0");
    xml += BOOLEAN_ETAG;
    xml += VALUE_ETAG;
    return xml;
  }

  // Int
  bool XmlRpcValue::intFromXml(std::string const& valueXml, int* offset)
  {
    const char* valueStart = valueXml.c_str() + *offset;
    char* valueEnd;
    long ivalue = strtol(valueStart, &valueEnd, 10);
    if (valueEnd == valueStart)
      return false;

    _type = TypeInt;
    _value.asInt = int(ivalue);
    *offset += int(valueEnd - valueStart);
    return true;
  }

  std::string XmlRpcValue::intToXml() const
  {
    char buf[256];
    snprintf(buf, sizeof(buf)-1, "%d", _value.asInt);
    buf[sizeof(buf)-1] = 0;
    std::string xml = VALUE_TAG;
    xml += I4_TAG;
    xml += buf;
    xml += I4_ETAG;
    xml += VALUE_ETAG;
    return xml;
  }

  // Double
  bool XmlRpcValue::doubleFromXml(std::string const& valueXml, int* offset)
  {
    const char* valueStart = valueXml.c_str() + *offset;
    char* valueEnd;
    double dvalue = strtod(valueStart, &valueEnd);
    if (valueEnd == valueStart)
      return false;

    _type = TypeDouble;
    _value.asDouble = dvalue;
    *offset += int(valueEnd - valueStart);
    return true;
  }

  std::string XmlRpcValue::doubleToXml() const
  {
    char buf[256];
    snprintf(buf, sizeof(buf)-1, getDoubleFormat().c_str(), _value.asDouble);
    buf[sizeof(buf)-1] = 0;

    std::string xml = VALUE_TAG;
    xml += DOUBLE_TAG;
    xml += buf;
    xml += DOUBLE_ETAG;
    xml += VALUE_ETAG;
    return xml;
  }

  // String
  bool XmlRpcValue::stringFromXml(std::string const& valueXml, int* offset)
  {
    size_t valueEnd = valueXml.find('<', *offset);
    if (valueEnd == std::string::npos)
      return false;     // No end tag;

    _type = TypeString;
    _value.asString = new std::string(XmlRpcUtil::xmlDecode(valueXml.substr(*offset, valueEnd-*offset)));
    *offset += int(_value.asString->length());
    return true;
  }

  std::string XmlRpcValue::stringToXml() const
  {
    std::string xml = VALUE_TAG;
    xml += STRING_TAG;// optional
    xml += XmlRpcUtil::xmlEncode(*_value.asString);
    xml += STRING_ETAG;
    xml += VALUE_ETAG;
    return xml;
  }

  // DateTime (stored as a struct tm)
  bool XmlRpcValue::timeFromXml(std::string const& valueXml, int* offset)
  {
    size_t valueEnd = valueXml.find('<', *offset);
    if (valueEnd == std::string::npos)
      return false;     // No end tag;

    std::string stime = valueXml.substr(*offset, valueEnd-*offset);

    struct tm t;
    if (sscanf(stime.c_str(),"%4d%2d%2dT%2d:%2d:%2d",&t.tm_year,&t.tm_mon,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec) != 6)
      return false;

    t.tm_isdst = -1;
    _type = TypeDateTime;
    _value.asTime = new struct tm(t);
    *offset += int(stime.length());
    return true;
  }

  std::string XmlRpcValue::timeToXml() const
  {
    struct tm* t = _value.asTime;
    char buf[20];
    snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d", 
      t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
    buf[sizeof(buf)-1] = 0;

    std::string xml = VALUE_TAG;
    xml += DATETIME_TAG;
    xml += buf;
    xml += DATETIME_ETAG;
    xml += VALUE_ETAG;
    return xml;
  }


  // Base64
  bool XmlRpcValue::binaryFromXml(std::string const& valueXml, int* offset)
  {
    size_t valueEnd = valueXml.find('<', *offset);
    if (valueEnd == std::string::npos)
      return false;     // No end tag;

    _type = TypeBase64;
    std::string asString = valueXml.substr(*offset, valueEnd-*offset);
    _value.asBinary = new BinaryData();
    // check whether base64 encodings can contain chars xml encodes...

    // convert from base64 to binary
    int iostatus = 0;
   base64<char> decoder;
    std::back_insert_iterator<BinaryData> ins = std::back_inserter(*(_value.asBinary));
  decoder.get(asString.begin(), asString.end(), ins, iostatus);

    *offset += int(asString.length());
    return true;
  }


  std::string XmlRpcValue::binaryToXml() const
  {
    // convert to base64
    std::vector<char> base64data;
    int iostatus = 0;
   base64<char> encoder;
    std::back_insert_iterator<std::vector<char> > ins = std::back_inserter(base64data);
  encoder.put(_value.asBinary->begin(), _value.asBinary->end(), ins, iostatus, base64<>::crlf());

    // Wrap with xml
    std::string xml = VALUE_TAG;
    xml += BASE64_TAG;
    xml.append(base64data.begin(), base64data.end());
    xml += BASE64_ETAG;
    xml += VALUE_ETAG;
    return xml;
  }


  // Array
  bool XmlRpcValue::arrayFromXml(std::string const& valueXml, int* offset)
  {
    if ( ! XmlRpcUtil::nextTagIs(DATA_TAG, valueXml, offset))
      return false;

    _type = TypeArray;
    _value.asArray = new ValueArray;
    XmlRpcValue v;
    while (v.fromXml(valueXml, offset))
      _value.asArray->push_back(v);       // copy...

    // Skip the trailing </data>
    (void) XmlRpcUtil::nextTagIs(DATA_ETAG, valueXml, offset);
    return true;
  }


  // In general, its preferable to generate the xml of each element of the
  // array as it is needed rather than glomming up one big string.
  std::string XmlRpcValue::arrayToXml() const
  {
    std::string xml = VALUE_TAG;
    xml += ARRAY_TAG;
    xml += DATA_TAG;

    int s = int(_value.asArray->size());
    for (int i=0; i<s; ++i)
       xml += _value.asArray->at(i).toXml();

    xml += DATA_ETAG;
    xml += ARRAY_ETAG;
    xml += VALUE_ETAG;
    return xml;
  }


  // Struct
  bool XmlRpcValue::structFromXml(std::string const& valueXml, int* offset)
  {
    _type = TypeStruct;
    _value.asStruct = new ValueStruct;

    while (XmlRpcUtil::nextTagIs(MEMBER_TAG, valueXml, offset)) {
      // name
      const std::string name = XmlRpcUtil::parseTag(NAME_TAG, valueXml, offset);
      // value
      XmlRpcValue val(valueXml, offset);
      if ( ! val.valid()) {
        invalidate();
        return false;
      }
      const std::pair<const std::string, XmlRpcValue> p(name, val);
      _value.asStruct->insert(p);

      (void) XmlRpcUtil::nextTagIs(MEMBER_ETAG, valueXml, offset);
    }
    return true;
  }


  // In general, its preferable to generate the xml of each element
  // as it is needed rather than glomming up one big string.
  std::string XmlRpcValue::structToXml() const
  {
    std::string xml = VALUE_TAG;
    xml += STRUCT_TAG;

    ValueStruct::const_iterator it;
    for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it) {
      xml += MEMBER_TAG;
      xml += NAME_TAG;
      xml += XmlRpcUtil::xmlEncode(it->first);
      xml += NAME_ETAG;
      xml += it->second.toXml();
      xml += MEMBER_ETAG;
    }

    xml += STRUCT_ETAG;
    xml += VALUE_ETAG;
    return xml;
  }



  // Write the value without xml encoding it
  std::ostream& XmlRpcValue::write(std::ostream& os) const {
    switch (_type) {
      default:           break;
      case TypeBoolean:  os << _value.asBool; break;
      case TypeInt:      os << _value.asInt; break;
      case TypeDouble:   os << _value.asDouble; break;
      case TypeString:   os << *_value.asString; break;
      case TypeDateTime:
        {
          struct tm* t = _value.asTime;
          char buf[20];
          snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d", 
            t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
          buf[sizeof(buf)-1] = 0;
          os << buf;
          break;
        }
      case TypeBase64:
        {
          int iostatus = 0;
          std::ostreambuf_iterator<char> out(os);
          base64<char> encoder;
          encoder.put(_value.asBinary->begin(), _value.asBinary->end(), out, iostatus, base64<>::crlf());
          break;
        }
      case TypeArray:
        {
          int s = int(_value.asArray->size());
          os << '{';
          for (int i=0; i<s; ++i)
          {
            if (i > 0) os << ',';
            _value.asArray->at(i).write(os);
          }
          os << '}';
          break;
        }
      case TypeStruct:
        {
          os << '[';
          ValueStruct::const_iterator it;
          for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it)
          {
            if (it!=_value.asStruct->begin()) os << ',';
            os << it->first << ':';
            it->second.write(os);
          }
          os << ']';
          break;
        }
      
    }
    
    return os;
  }

} // namespace XmlRpc


// ostream
std::ostream& operator<<(std::ostream& os, XmlRpc::XmlRpcValue& v) 
{ 
  // If you want to output in xml format:
  //return os << v.toXml(); 
  return v.write(os);
}

Test.c
#include <iostream>
#include "src/XmlRpc.h"

using namespace XmlRpc;

int main(int argc, char* argv[])
{

   XmlRpcClient c("xmlrpc.secondlife.com", 80, "/cgi-bin/xmlrpc.cgi");
   
   XmlRpcValue testLSL,result;   

   testLSL["Channel"] = "83af2b8d-80fa-1db6-b35a-b9c0c2dc8670";
   testLSL["IntValue"] = 50;
   testLSL["StringValue"] = "Hello World!";
      
   if (c.execute("llRemoteData", testLSL, result)) 
     {
 std::cout << "Returned:\n";
 std::cout << "\t" << result["IntValue"] << "\n\t" << result["StringValue"] << "\n\n";
     }
   else 
     {
 std::cout << "Error calling 'llRemoteData'\n\n";
     }
   
   return 0;
}



C++ Example 2


This C++ example uses the KDE 3.x libraries (Linux) and reads the XML data from a file.

test.h
#include <kio/job.h>

class Test : public QObject
{
	Q_OBJECT

	public:
		Test();

	protected slots:
		void requestData
			(KIO::Job *job, const QByteArray &data);
		void requestResult
			(KIO::Job *job);
};

test.cpp
#include "test.moc"

#include <kapp.h>
#include <kaboutdata.h>
#include <kcmdlineargs.h>

#include <kfile.h>
#include <stream.h>

int main(int argc, char **argv)
{
	KAboutData about("test", "Test", "0.1",
		"A test of communication with SL", KAboutData::License_GPL,
	       	"Copyright (c) 2007 LSL wiki");
	KCmdLineArgs::init(argc, argv, &about);
	KApplication application(false, false);

	Test *test = new Test();

	return application.exec();
}

Test::Test()
	: QObject()
{
	KIO::SimpleJob *job;
	KURL address("http://xmlrpc.secondlife.com/cgi-bin/xmlrpc.cgi");
	QFile testFile("test.xml");
	QByteArray toSend;

	if (!testFile.open(IO_ReadOnly))
	{
		cerr << "Failed to open XML file";
		return;
	}
	toSend = testFile.readAll();
	testFile.close();

	job = KIO::http_post(address, toSend, false);
	job->addMetaData("accept", "text/xml, */*");
	job->addMetaData("content-type", "Content-type: application/x-www-form-urlencoded");

	connect(job,
		SIGNAL(data(KIO::Job *, const QByteArray &)),
		this,
		SLOT(requestData(KIO::Job *, const QByteArray &)));
	connect(job,
		SIGNAL(result(KIO::Job *)),
		this,
		SLOT(requestResult(KIO::Job *)));
}

void Test::requestData(KIO::Job *job, const QByteArray &data)
{
	cout << data;
}

void Test::requestResult(KIO::Job *job)
{
	if (job->error())
		cerr << "Failure";
       	else cout << "Transfer succeeded";
}

test.moc

Is generated automatically using Qt's "moc" utility.



Java


This Java example uses the XML-RPC implementation available from the Apache Web Services Project. This example uses an outdated version of the library... does anyone want to fix it? -Fixed using v3.0 of apache. Revised code below. DeleriumHannibal

import java.net.URL;
import java.util.Hashtable;
import java.util.Vector;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;

public class RpcTest {
    
    public static void main(String[] args) {
        /*
         * Put the arguments into an XML-RPC struct, represented by
         * a Java Hashtable.
         */
        Hashtable s = new Hashtable();
        s.put("Channel", "5b90c3ad-a641-fc2c-55e1-dfcc3eefc7cd");
        s.put("IntValue", new Integer(17));
        s.put("StringValue", "Hello, Alexander!");
        
        /*
         * Argument list for the call is a vector containing the struct.
         */
        Vector v = new Vector();
        v.add(s);
        
        try {
            XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
            config.setServerURL(new URL("http://xmlrpc.secondlife.com:80/cgi-bin/xmlrpc.cgi"));
            XmlRpcClient client = new XmlRpcClient();
            client.setConfig(config);
            Object result = client.execute("llRemoteData", v);
            if (result != null)
                System.out.println("Result class: " + result.getClass().getName());
        } catch(Exception e) {
            System.out.println("Failed: " + e);
        }
    }
    
}



JavaScript


This JavaScript example uses the JavaScript O Lait http://jsolait.net/index.xhtml library by Jan-Klaas Kollhof. However you should note that the default settings on most browsers do not allow XML-RPC to external websites.

<script type="text/javascript" src="http://jsolait.net/examples/xmlrpc/jsolait/init.js"></script>  <!--- You can replace these with local copies (download from http://jsolait.net/doc/index.xhtml) --->
<script type="text/javascript" src="http://jsolait.net/examples/xmlrpc/jsolait/lib/urllib.js"></script>
<script type="text/javascript" src="http://jsolait.net/examples/xmlrpc/jsolait/lib/xml.js"></script>
<script type="text/javascript" src="http://jsolait.net/examples/xmlrpc/jsolait/lib/xmlrpc.js"></script>
<script type="text/javascript" >
var xmlrpc=null;
try{
    var xmlrpc = importModule("xmlrpc");
}catch(e){
    reportException(e);
    throw "importing of xmlrpc module failed.";
}

function send_rpc(){
    var addr = "http://xmlrpc.secondlife.com/cgi-bin/xmlrpc.cgi";

    var sChannel = "0d58c21c-b56f-57df-745f-9ccd0e06df49";  // Add your ChannelID and arguments (can be pulled from textboxes)
    var iValue = 17;
    var sString = "Hello, Alexander!";
    var evalStr = {"Channel" : sChannel, "IntValue" : iValue, "StringValue" : sString};
    
    try{
        var service = new xmlrpc.ServiceProxy(addr);
        var rslt = service.llRemoteData(evalStr);  // Result object
		
        alert(rslt["StringValue"]);  // Returns String Value
		alert(rslt["IntValue"]);  // Returns Int Value
    }catch(e){
        var em;
        if(e.toTraceString){
            em=e.toTraceString();
        }else{
            em = e.message;
        }
        alert("Error trace: \n\n" + em);
    }
    return false;
}
</script>



Perl

Here's an example in Perl. It uses the RPC::XML module that is available from CPAN.
The values for $key, $ival and $sval need to be valid of course.
require RPC::XML;
require RPC::XML::Client;

my $client = RPC::XML::Client->new('http://xmlrpc.secondlife.com:80/cgi-bin/xmlrpc.cgi');

my $request = RPC::XML::request->new('llRemoteData', RPC::XML::struct->new(
   'Channel'   => RPC::XML::string->new($key),
   'IntValue' => RPC::XML::int->new($ival),
   'StringValue' => RPC::XML::string->new($sval)
   )
);

my $response = $client->simple_request($request);
if (!$response) {
   print $RPC::XML::ERROR, "\n";
} else {
   print $response->{StringValue}, "\n";
   print $response->{IntValue}, "\n";
}



PHP Example 1

Here's an implementation in PHP, using PHP's XML-RPC library. Note that you may need to compile it into your PHP build. Users of the PHP Windows binaries just need to add extension=php_xmlrpc.dll into their php.ini.
<?php
 
function llRemoteData($channel$intvalue$stringvalue) {
  
$host "xmlrpc.secondlife.com";
  
$port 80;
  
$uri "/cgi-bin/xmlrpc.cgi";
  
$request xmlrpc_encode_request('llRemoteData',
   array( 
'Channel' => $channel,
    
'IntValue' => $intvalue,
    
'StringValue' => $stringvalue));
  
$fp fsockopen($host$port$errno$errstr);
  
$query "POST " $uri " HTTP/1.0\n" .
    
"User_Agent: PHP XML-RPC Interface\n" .
    
"Host: " $host "\n" .
    
"Content-Type: text/xml\n" .
    
"Content-Length: " strlen($request) . "\n\n" .
    
$request "\n";
 
  if (!
fputs($fp$querystrlen($query)))
   return 
NULL// some sort of write error occured
 
  
$xmlresp "";
 
//I replaced some code that was here but did not work. This should work just as well, in less code and quicker ;p
//read the maximum amount (if you have more bytes than 8192, this method will not work)
 
$response fread($fp8192);
//grab the XML
 
$xmlresp = (substr($responsestrpos($response"\r\n\r\n")+4));
 
  
fclose($fp);
  if (
$xmlresp == "")
   return 
NULL;
  else
   return 
xmlrpc_decode($xmlresp);
 }
?>



PHP Example 2

Here is a way to send RPC without the need of special includes
<?php
  
function postToHost($host$path$data_to_send) {
    
$fp fsockopen($host80);
    
fputs($fp"POST $path HTTP/1.1\r\n");
    
fputs($fp"Host: $host\r\n");
    
fputs($fp"Content-type: application/x-www-form-urlencoded\r\n");
    
fputs($fp"Content-length: "strlen($data_to_send) ."\r\n");
    
fputs($fp"Connection: close\r\n\r\n");
    
fputs($fp$data_to_send);
    
$res "";
    while(!
feof($fp)) {
        
$res .= fgets($fp128);
    }
    
fclose($fp);
    return 
substr($resstrpos($res"\r\n\r\n"));;
  }
  
  function 
parseResponse($response) {
    
$result = array();
    if (
preg_match_all('#<name>(.+)</name><value><(string|int)>(.*)</\2></value>#U'$response$regsPREG_SET_ORDER)) {
      foreach(
$regs as $key=>$val) {
        
$result[$val[1]] = $val[3];
      }
    }
    return 
$result;
  }
  
  function 
sendRequest($channel$intValue$stringValue) {
    
$channel htmlspecialchars($channel);
    
$int = (int)$intValue;
    
$string htmlspecialchars($stringValue);
    
    
$data '<?xml version="1.0"?>';
    
$data .= '<methodCall>';
    
$data .= '<methodName>llRemoteData</methodName>';
    
$data .= '<params><param><value><struct>';
    
$data .= '<member><name>Channel</name><value><string>'.$channel.'</string></value></member>';
    
$data .= '<member><name>IntValue</name><value><int>'.$int.'</int></value></member>';
    
$data .= '<member><name>StringValue</name><value><string>'.$string.'</string></value></member>';
    
$data .= '</struct></value></param></params></methodCall>';

    return 
parseResponse(postToHost("xmlrpc.secondlife.com","/cgi-bin/xmlrpc.cgi"$data));
  }
?>



Python Example 1

Client example in python using xmlrpclib (included in Python 2.2+):
#!/usr/local/bin/python

from xmlrpclib import ServerProxy;
import sys;

def llRemoteData(Channel, Int, String):
        client = ServerProxy("http://xmlrpc.secondlife.com/cgi-bin/xmlrpc.cgi");
        return client.llRemoteData({"Channel" : Channel, "IntValue" : Int, "StringValue" : String});


reply = llRemoteData("9307b83e-0739-63d5-86a5-f510aded12f4", 0, "Hello from " + sys.platform);

for name, value in reply.iteritems():
        print name, value;



Python Example 2

Another python example using the python-xmlrpc module which comes as a nice debian package:
#!/usr/bin/python
import xmlrpc
client = xmlrpc.client("xmlrpc.secondlife.com", 80, "/cgi-bin/xmlrpc.cgi")
print client.execute("llRemoteData", [{"Channel": "2ac9fac6-6194-8e2a-2415-06257dea4a72", "IntValue": 0, "StringValue": "yourmessage"}])



Python Example 3

Another python example using twisted:
from twisted.web.xmlrpc import Proxy
from twisted.internet import reactor

def printValue(value):
    print repr(value)
    reactor.stop()

def printError(error):
    print 'error', error
    reactor.stop()

proxy = Proxy('http://xmlrpc.secondlife.com/cgi-bin/xmlrpc.cgi')
proxy.callRemote('llRemoteData', {"Channel": "a9c9b2e5-2b91-3e3e-ef98-a26b83d21fcd", "IntValue": 0, "StringValue": "yourmessage"}).addCallbacks(printValue, printError)
reactor.run()




Ruby

Here is a Ruby example using xmlrpc4r:
#!/usr/bin/ruby

require "xmlrpc/client"

server = XMLRPC::Client.new("xmlrpc.secondlife.com","/cgi-bin/xmlrpc.cgi")

begin
        result = server.call("llRemoteData", {
                "Channel"     => channel,
                "StringValue" => sdata,
                "IntValue"    => idata
        })

        puts "Channel:     #{result['Channel']}"
        puts "StringValue: #{result['StringValue']}"
        puts "IntValue:    #{result['IntValue']}"

rescue XMLRPC::FaultException => e
        puts "Error: #{e.faultCode} (#{e.faultString})"
end

XMLRPC / XMLRPCDiscussion
There are 4 comments on this page. [Display comments/form]