5

So I've been looking around the internet for a basic example of parsing JSON using libcurl and jsoncpp but I've not been able to find one.

Could someone please point me in the right direction or specify here, a simple example of using libcurl and jsoncpp, downloading json from a specified webpage (the link itself ending in .json so it will be pulling json directly) parsing it and printing it.

All help is appreciated. Thanks!

Euden

Ben Crazed Up Euden
  • 353
  • 2
  • 7
  • 18
  • 2
    Parsing JSON with [**jsoncpp**](https://github.com/open-source-parsers/jsoncpp) and downloading content with [**libcurl**](http://curl.haxx.se/libcurl/) are two distinct activities, both of which are considerably documented on their respective sites. So what is the specific problem in stitching them together (i.e. download + parse = success)? – WhozCraig Jul 22 '14 at 10:20
  • I'd like a simple example of downloading and parsing if possible. – Ben Crazed Up Euden Jul 22 '14 at 12:48

2 Answers2

15

Here's a self-contained example to a) HTTP GET a JSON object via libcurl and then b) parse it with JsonCpp. @WhozCraig is correct to say that these are two totally separate activities, but I happen to have a project that does both so I aggregated this small sample that fetches and parses the JSON from this nifty page.

If you put this code in a file called main.cpp, then you can compile, link, and run (assuming libcurl and libjsoncpp are available on your path) with:

g++ main.cpp -ljsoncpp -lcurl -o example.out && ./example.out

// main.cpp
#include <cstdint>
#include <iostream>
#include <memory>
#include <string>

#include <curl/curl.h>
#include <json/json.h>

namespace
{
    std::size_t callback(
            const char* in,
            std::size_t size,
            std::size_t num,
            std::string* out)
    {
        const std::size_t totalBytes(size * num);
        out->append(in, totalBytes);
        return totalBytes;
    }
}

int main()
{
    const std::string url("http://date.jsontest.com/");

    CURL* curl = curl_easy_init();

    // Set remote URL.
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());

    // Don't bother trying IPv6, which would increase DNS resolution time.
    curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);

    // Don't wait forever, time out after 10 seconds.
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);

    // Follow HTTP redirects if necessary.
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

    // Response information.
    int httpCode(0);
    std::unique_ptr<std::string> httpData(new std::string());

    // Hook up data handling function.
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);

    // Hook up data container (will be passed as the last parameter to the
    // callback handling function).  Can be any pointer type, since it will
    // internally be passed as a void pointer.
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpData.get());

    // Run our HTTP GET command, capture the HTTP response code, and clean up.
    curl_easy_perform(curl);
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
    curl_easy_cleanup(curl);

    if (httpCode == 200)
    {
        std::cout << "\nGot successful response from " << url << std::endl;

        // Response looks good - done using Curl now.  Try to parse the results
        // and print them out.
        Json::Value jsonData;
        Json::Reader jsonReader;

        if (jsonReader.parse(*httpData, jsonData))
        {
            std::cout << "Successfully parsed JSON data" << std::endl;
            std::cout << "\nJSON data received:" << std::endl;
            std::cout << jsonData.toStyledString() << std::endl;

            const std::string dateString(jsonData["date"].asString());
            const std::size_t unixTimeMs(
                    jsonData["milliseconds_since_epoch"].asUInt64());
            const std::string timeString(jsonData["time"].asString());

            std::cout << "Natively parsed:" << std::endl;
            std::cout << "\tDate string: " << dateString << std::endl;
            std::cout << "\tUnix timeMs: " << unixTimeMs << std::endl;
            std::cout << "\tTime string: " << timeString << std::endl;
            std::cout << std::endl;
        }
        else
        {
            std::cout << "Could not parse HTTP data as JSON" << std::endl;
            std::cout << "HTTP data was:\n" << *httpData.get() << std::endl;
            return 1;
        }
    }
    else
    {
        std::cout << "Couldn't GET from " << url << " - exiting" << std::endl;
        return 1;
    }

    return 0;
}

Output looks like:

Got successful response from http://date.jsontest.com/
Successfully parsed JSON data

JSON data received:
{
   "date" : "03-09-2015",
   "milliseconds_since_epoch" : 1425938476314,
   "time" : "10:01:16 PM"
}

Natively parsed:
    Date string: 03-09-2015
    Unix timeMs: 1425938476314
    Time string: 10:01:16 PM
ConnorManning
  • 299
  • 3
  • 14
  • Unfortunately this now yields build errors as methods used are deprecated. Is there a current working example? – BriCo84 Dec 16 '20 at 21:25
0

The code provided above by @ConnorManning still works well in 2022 (I cannot comment there because I do not have enough "points" for that)

However, after compilation it might SIGSEGV on url, so here is the quick fix. Change line:

const std::string url("http://date.jsontest.com/");

into

const char* url = "http://date.jsontest.com/";

Compile the same way and it should work well.

  • Considering the original code uses `url.c_str()`, your modification shouldn't make any difference. If you are having a segmentation fault it's probably somewhere else. – Fabio says Reinstate Monica Nov 28 '22 at 00:38
  • Yes, not on that line, but on each line which used `url`, like this one: `std::cout << "\nGot successful response from " << url << std::endl;` It was hard for me to believe it, but `gdb` told me so and verified it by commenting out such lines. – Ondrej Jombik Nov 28 '22 at 00:48
  • Printing a string with `std::cout` cannot give a segfault. If you see it, it must be something else. For example, an out-of-bound access overwriting part of the string. Note that gdb can tell you where the crash happens (i.e. when running `cout`) but it doesn't tell you the cause (another line that has overwritten part of the string). That would require a tool like valgrind. Also, under Connor's answer there's a comment saying that the methods that are used are deprecated. It could be that they work in a different way now, and that they can't be used like that. – Fabio says Reinstate Monica Nov 28 '22 at 10:51
  • In any case, I can't believe that by replacing a `const std::string` with a `const char *` you have solved a segmentation fault that happens when printing the string. If you are using that code in production, be VERY careful. The underlying issue is still there, and your program might crash any moment. – Fabio says Reinstate Monica Nov 28 '22 at 10:55