XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

Building XML-RPC Clients in C
by Joe Johnston | Pages: 1, 2, 3, 4

Listing 7 hints at the reference counting that Kidd's XML-RPC library does. He tries to shield the user from the details of memory management, but you must tell the system when you are done with xmlrpc_value data (see line 73). There are also two convenient functions (lines 76, 77) for cleaning up other memory that was allocated behind the scenes.

Listing 7: xmlrpc_debug.c, part 6


    72      /* Dispose of our result value. */
    73      xmlrpc_DECREF(result);
    74      
    75      /* Shutdown our XML-RPC client library. */
    76      xmlrpc_env_clean(&env);
    77      xmlrpc_client_cleanup();
    78  
    79      free(url);
    80  
    81      return 0;
    82  }
    83  

Listing 8 shows how the six simplest data types are decoded. The tricky part is knowing which "format" string to pass to xmlrpc_parse_value. You can use this code as a guide, but also look at the aforementioned overview.txt for the gory details. Notice that after calling this conversion function, any errors that may have occurred will be reported by die_if_fault_occurred (which is code ripped entirely from Eric Kidd's examples).

Listing 8: xmlrpc_debug.c, part 7


    84  /*
    85    subs
    86   */
    87  void print_values( xmlrpc_env* env, xmlrpc_value* in ){
    88  
    89      /* What did we get back? */
    90      switch (xmlrpc_value_type(in)) {
    91        case (XMLRPC_TYPE_INT):
    92          printf("Got an integer: %d\n", get_int(env, in));
    93          break;
    94        case (XMLRPC_TYPE_BOOL):
    95          printf("Got a boolean: %d\n", get_boolean(env, in));
    96          break;
    97        case (XMLRPC_TYPE_DOUBLE):
    98          printf("Got a double: %g\n", get_double(env, in));
    99          break;
   100        case (XMLRPC_TYPE_DATETIME):
   101          printf("Got an ISO8601 timestamp: %s\n", 
                      get_timestamp(env, in));
   102          break;
   103        case (XMLRPC_TYPE_STRING):
   104          printf("Got a string: %s\n", get_string(env, in));
   105          break;
   106        case (XMLRPC_TYPE_BASE64):
   107          printf("Got a base64 string: %s\n", 
                      get_base64(env, in));
   108          break;
   109        case (XMLRPC_TYPE_ARRAY):
   110          printf("Got an array:\n"); 
   111          get_array(env, in);
   112          break;
   113        case (XMLRPC_TYPE_STRUCT):
   114          printf("Got a struct\n");
   115          get_struct(env, in);
   116          break;
   117        case (XMLRPC_TYPE_C_PTR):
   118          printf("Got a C pointer?!\n");
   119          break;
   120        case (XMLRPC_TYPE_DEAD):
   121          printf("Got a 0xDEADr?!\n");
   122          break;
   123        default:
   124          printf("UNKNOWN XML-RPC DATATYPE\n");
   125      }
   126  }

Listing 9 is a bit long, but it's a pretty simple switch statement. The XML-RPC library defines several constants with which the xmlrpc_value that was passed in can be identified. Most of these types should be self-evident. In order to map XML-RPC values to C values, we need to call xmlrpc_parse_value. Examples of this will be seen in the small helper functions that begin with "get_". The last two cases are internal datatypes that won't normally occur, but are shown for the sake of completeness.

Listing 9: xmlrpc_debug.c, part 8


   127  int get_int(xmlrpc_env* env, xmlrpc_value* in){
   128    int i;
   129    xmlrpc_parse_value(env, in, "i", &i);
   130    die_if_fault_occurred(env);
   131    return(i);
   132  }
   133  
   134  
   135  int get_boolean(xmlrpc_env* env, xmlrpc_value* in){
   136    int i;
   137    xmlrpc_parse_value(env, in, "b", &i);
   138    die_if_fault_occurred(env);
   139    return(i);
   140  }
   141  
   142  double get_double(xmlrpc_env* env, xmlrpc_value* in){
   143    double d;
   144    xmlrpc_parse_value(env, in, "d", &d);
   145    die_if_fault_occurred(env);
   146    return(d);
   147  }
   148  
   149  
   150  char* get_timestamp(xmlrpc_env* env, xmlrpc_value* in){
   151    char *s;
   152    
   153    xmlrpc_parse_value(env, in, "8", &s);
   154    die_if_fault_occurred(env);
   155    return(s);
   156  }
   157  
   158  char* get_string(xmlrpc_env* env, xmlrpc_value* in){
   159    char* s;
   160  
   161    xmlrpc_parse_value(env, in, "s", &s);
   162    die_if_fault_occurred(env);
   163    return(s);
   164  }
   165  
   166  char* get_base64(xmlrpc_env* env, xmlrpc_value* in) {
   167    char *s;
   168  
   169    xmlrpc_parse_value(env, in, "6", &s);
   170    die_if_fault_occurred(env);
   171    return(s);
   172  }
   173  

Listing 10 shows how to handle the simplest aggregate type, the array. Naively calling xmlrpc_parse_value won't work here because each element can be a different data type. Fortunately, the size of the array can be determined with a call to xmlrpc_array_size. Then, it's a simple matter to iterate through the array, retrieving each element with a call to xmlrpc_array_get. In a fine display of code reuse, this element is passed to print_values.

Listing 10: xmlrpc_debug.c, part 9


   174  void get_array(xmlrpc_env* env, xmlrpc_value* in){
   175    int i, size = 0;
   176    xmlrpc_value *el;
   177  
   178    size = xmlrpc_array_size(env, in);
   179    die_if_fault_occurred(env);
   180  
   181    for(i=0; i < size; i++){
   182      el = xmlrpc_array_get_item( env, in, i);
   183      die_if_fault_occurred(env);
   184      print_values(env, el);
   185    }
   186  }
   187  

Pages: 1, 2, 3, 4

Next Pagearrow