parsing JSON with jansson in C

19,614

The root element of your JSON string is an object, not an array. Arrays in JSON are denoted with square brackets [ and ], and objects are denoted with curly brackets { and }. You won't need to iterate over the “object” root element if you already know what keys you want to access, just use json_object_get(root, "keyname"); until you have accessed all the values you need.

Share:
19,614
Asphyxiated
Author by

Asphyxiated

Updated on July 10, 2022

Comments

  • Asphyxiated
    Asphyxiated almost 2 years

    So I have been working on writing a program in C that can access the API's of various cryptocurrency sites like www.cryptsy.com, I have the cURL portion figured out and gave the program spit out the JSON data into a char* variable which looks like this:

    {"success":"1","return":{"balances_available":{"ALF":"0.00000000","AMC":"0.00000000","ADT":"0.00000000","ANC":"0.00000000","ARG":"0.00000000","ASC":"0.00000000","BQC":"0.00000000","BTB":"0.00000000","BTC":"0.00535673","BTG":"0.00000000","CAP":"0.00000000","BTE":"0.00000000","CSC":"0.00000000","CNC":"0.00000000","COL":"0.00000000","CPR":"0.00000000","CLR":"0.00000000","CMC":"0.00000000","CRC":"0.00000000","BUK":"0.00000000","CGB":"0.00000000","Points":"0.00911000","DVC":"0.00000000","DMD":"0.00000000","DGC":"0.00000000","DBL":"0.00000000","ELC":"0.00000000","ELP":"0.00000000","EMD":"0.00000000","EZC":"0.00000000","FST":"0.00000000","FTC":"0.00000000","FLO":"0.00000000","FRK":"0.00000000","FRC":"0.00000000","GLX":"0.00000000","GME":"0.00000000","GLC":"0.00000000","GLD":"0.00000000","GDC":"0.00000000","HBN":"0.00000000","HYC":"0.00000000","IFC":"0.00000000","IXC":"0.00000000","XJO":"0.00000000","JKC":"0.00000000","KGC":"0.00000000","LTC":"0.00000000","LK7":"0.00000000","LKY":"0.00000000","MST":"0.00000000","MEC":"0.00000000","MEM":"0.00000000","MNC":"0.00000000","NMC":"0.00000000","NAN":"0.00000000","NEC":"0.00000000","NET":"0.00000000","NBL":"0.00000000","NRB":"0.00000000","NVC":"0.00000000","ORB":"0.00000000","PYC":"0.00000000","PPC":"0.00000000","CENT":"0.00000000","PHS":"0.00000000","PXC":"0.00000000","XPM":"0.00000000","PTS":"0.00000000","QRK":"0.00000000","RED":"0.00000000","RYC":"0.00000000","SRC":"0.00000000","SXC":"0.00000000","SPT":"0.00000000","SBC":"0.00000000","STR":"0.00000000","TAG":"0.00000000","TEK":"0.00000000","TRC":"0.00000000","TIX":"0.00000000","WDC":"0.00000000","XNC":"0.00000000","YAC":"0.00000000","ZET":"0.00000000"},"balances_hold":{"ALF":"0.00000000","AMC":"0.00000000","ADT":"0.00000000","ANC":"0.00000000","ARG":"0.00000000","ASC":"0.00000000","BQC":"0.00000000","BTB":"0.00000000","BTC":"0.00000000","BTG":"0.00000000","CAP":"0.00000000","BTE":"0.00000000","CSC":"0.00000000","CNC":"0.00000000","COL":"0.00000000","CPR":"0.00000000","CLR":"0.00000000","CMC":"0.00000000","CRC":"0.00000000","BUK":"0.00000000","CGB":"0.00000000","Points":"0.00000000","DVC":"0.00000000","DMD":"0.00000000","DGC":"0.00000000","DBL":"0.00000000","ELC":"0.00000000","ELP":"0.00000000","EMD":"0.00000000","EZC":"0.00000000","FST":"0.00000000","FTC":"0.00000000","FLO":"0.00000000","FRK":"0.00000000","FRC":"0.00000000","GLX":"0.00000000","GME":"0.00000000","GLC":"0.00000000","GLD":"0.00000000","GDC":"0.00000000","HBN":"0.00000000","HYC":"0.00000000","IFC":"0.00000000","IXC":"0.00000000","XJO":"0.00000000","JKC":"0.00000000","KGC":"0.00000000","LTC":"1.10231195","LK7":"0.00000000","LKY":"10.36912507","MST":"0.00000000","MEC":"0.00000000","MEM":"0.00000000","MNC":"0.00000000","NMC":"0.00000000","NAN":"0.00000000","NEC":"0.00000000","NET":"0.00000000","NBL":"0.00000000","NRB":"0.00000000","NVC":"0.00000000","ORB":"0.00000000","PYC":"0.00000000","PPC":"0.00000000","CENT":"0.00000000","PHS":"0.00000000","PXC":"0.00000000","XPM":"0.00000000","PTS":"0.00000000","QRK":"0.00000000","RED":"0.00000000","RYC":"0.00000000","SRC":"0.00000000","SXC":"0.00000000","SPT":"0.00000000","SBC":"0.00000000","STR":"0.00000000","TAG":"0.00000000","TEK":"0.00000000","TRC":"0.83964122","TIX":"0.00000000","WDC":"0.00000000","XNC":"0.00000000","YAC":"0.00000000","ZET":"0.00000000"},"servertimestamp":1387347714,"servertimezone":"EST","serverdatetime":"2013-12-18 01:21:54","openordercount":3}}
    

    which looks like valid JSON data to me so I decided to try to use jansson to do the JSON parsing/decoding, which looks like this in my code:

    char *data;
    
    if ( argc < 2 )
    {
        fprintf( stderr, "Must provide URL to fetch.\n" );
        return 1;
    }
    //data = mmpool_api( argv[1] );
    data = cryptsy_api( argv[1] );
    
    json_t *root;
    json_error_t error;
    
    root = json_loads( data, 0, &error );
    if ( !root )
    {
        fprintf( stderr, "error: on line %d: %s\n", error.line, error.text );
        return 1;
    }
    if ( !json_is_array(root) )
    {
        fprintf( stderr, "error: root is not an array\n" );
        json_decref(root);
        return 1;
    }
    
    for( int i = 0; i < json_array_size(root); i++ )
    {
        json_t *data, *success, *returned, *bal_avail;
        const char *balance;
    
        data = json_array_get( root, i );
        if ( !json_is_object(data) )
        {
            fprintf( stderr, "error: data %d is not an object\n", i + 1 );
            json_decref(root);
            return 1;
        }
    
        success = json_object_get( data, "success" );
        if ( !json_is_number(success))
        {
            fprintf( stderr, "error: %d: success is not a number", i+1 );
            json_decref(root);
            return 1;
        }
    
        returned = json_object_get(data, "return" );
        if ( !json_is_object(returned) )
        {
            fprintf( stderr, "error: %d: return is not an object", i+1  );
            json_decref(root);
            return 1;
        }
    
        bal_avail = json_object_get( returned, "balances_available" );
        if ( !json_is_array( bal_avail ))
        {
            fprintf( stderr, "error: %d: bal_avail is not an array", i+1 );
            json_decref(root);
        }
    
        balance = json_string_value(bal_avail);
        printf( "%s %.*s\n",
            json_string_value(bal_avail),
            newline_offset(balance),
            balance);
    }
    json_decref(root);
    

    but the program just fails stating that root is not an array, so it dies on the second if statement after the JSON code starts. I have noticed that jansson has its own "request(url)" function that you can use to make a request to a server for the JSON data but to get the data I am getting you need to send a secret key/API key and hash them with SHA512 to get a valid response, this function does not seem to have the capability.

    I know that there are other libraries for C for decoding JSON data but I just wanted to make sure that I am not doing something wrong here before I switched to JSON-C or another library. Thanks

    EDIT::

    ok so I have tried to change the code to just parse through the 'root' object, but it seems to only go through the "return" and "success" keys.. perhaps I still dont fully understand but here is the code I am using now to try to parse everything, I read the jansson API guide and it says to use an iterator if you want to go over each and every key:value pair in the object like this:

    char *data;
    
    if ( argc < 2 )
    {
        fprintf( stderr, "Must provide URL to fetch.\n" );
        return 1;
    }
    //data = mmpool_api( argv[1] );
    data = cryptsy_api( argv[1] );
    
    json_t *root;
    json_error_t error;
    
    root = json_loads( data, 0, &error );
    if ( !root )
    {
        fprintf( stderr, "error: on line %d: %s\n", error.line, error.text );
        return 1;
    }
    
    const char *key;
    json_t *value;
    
    void *iter = json_object_iter( root );
    while( iter )
    {
        key = json_object_iter_key(iter);
        value = json_object_iter_value(iter);
    
        printf("Key: %s, Value: %f\n", key, json_real_value(value) );
    
        iter = json_object_iter_next(root, iter);
    }
    
    json_decref(root);
    

    but it comes out like this ( only the first two items are address and they are in reverse order):

    Key: return, Value: 0.000000 Key: success, Value: 0.000000

  • Asphyxiated
    Asphyxiated over 10 years
    I took what you said into consideration and changed the code abit, which is posted in the edit above, but perhaps I still dont understand exactly what you meant. If I try to access the "BTC" portion directly with json_t *btcBalance = json_object_get(root, "BTC"); printf( "Bitcoin Balance is %f\n", json_real_value(btcBalance)); but it just comes back 0.00000, same for json_integer_value() (with JSON_NUMBER_FORMAT macro in the printf formatter space)
  • TOMKA
    TOMKA over 10 years
    @Asphyxiated: That's because the values of all of those keys are strings. They are quoted "like this" so they will always be interpreted as strings. Integer literals should appear without quotes, e.g. {"success":1} and real literals should also appear without quotes, e.g. {"BTC":2.3456}. Since everything in your JSON string is quoted, everything is a string.
  • TOMKA
    TOMKA over 10 years
    What you'll need to do is get the string value, and use a function like strtod to convert to a double or strtol to convert to a long, etc.
  • TOMKA
    TOMKA over 10 years
    Keep in mind that "return" is a key whose value is another object, so you need to query the object returned by json_object_get(root, "return"), possibly by using the "balances_available" key, then query that object with the "BTC" key, and then turn the string into a double using strtod. Note that doubles are not accurate enough for currency purposes so unless you're only using it for simple math you should avoid converting to double, and consider an arbitrary precision math library (such as GMP) if you intend on handling these values as actual currency.