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

2
  • 2
    Parsing JSON with jsoncpp and downloading content with 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)? Commented Jul 22, 2014 at 10:20
  • I'd like a simple example of downloading and parsing if possible. Commented Jul 22, 2014 at 12:48

2 Answers 2

16

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
Sign up to request clarification or add additional context in comments.

1 Comment

Unfortunately this now yields build errors as methods used are deprecated. Is there a current working example?
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.

4 Comments

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.
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.
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.
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.