Friday, February 28, 2020

Working with JSON in C++

In this article, using JsonCpp library and wxJson library to work with JSON (JavaScript Object Notation) in C++ is discussed.


JsonCpp

A convenient way to use JsonCpp is adding its amalgamated source. At first, get the source from the official repository,

https://github.com/open-source-parsers/jsoncpp,

by entering the following command.

$ git clone https://github.com/open-source-parsers/jsoncpp.git


Go to the source directory, and generate the amalgamated files using

$ python amalgamate.py


The script generates two header files and one source file in 'dist' directory to be added to your project.

As an example create a C++ program, jtest.cpp, as follows.

#include <iostream>
#include <string>
#include <sstream>
#include <json/json.h>
using namespace std;
int main() {
    string document(("{\"Serial\" : {\"Baud\":9600, \"Parity\":\"Even\"}}"));
    stringstream ss;
    ss.str(document);
    // Json::Reader reader;
    Json::CharReaderBuilder reader;
    Json::Value obj;
    string errs;
    // reader.parse(document,obj);
    if(Json::parseFromStream(reader,ss,&obj,&errs)){
        cout << "Serial: baudrate = " << obj["Serial"]["Baud"].asUInt();
        cout << " parity = " << obj["Serial"]["Parity"].asString()<<endl;
    }    
    return 0;
}


Put the generated 'jsoncpp.cpp' in the same directory as 'jtest.cpp' and the headers, 'json.h' and 'json-forwards.h', in the subdirectory 'json' as it is. Thereafter, you can compile and run it as shown below.
$ g++ jtest.cpp jsoncpp.cpp -o jtest -I./
$ ./jtest


For visual studio, go to Property pages -> C/C++ -> General -> Additional Include Directories and add the directory for the source files.
$(ProjectDir)\source


More details for JsonCpp can be found at

https://en.wikibooks.org/wiki/JsonCpp [1]

wxJson

There is also a JSON implementation for wxWidgets called wxJSON. You can download the source files at the following link.

https://sourceforge.net/projects/wxcode/files/Components/wxJSON/

And extract
$ tar xvzf wxJSON-1.2.1.tar.gz


Go to extracted directory, and then subdirectory '/src' to copy the following three source files into your project.

jsonreader.cpp
jsonval.cpp
jsonwriter.cpp 


Again, in another subdirectory called '/include', copy 'wx' directory which include four header files.

json_defs.h
jsonreader.h
jsonval.h
jsonwriter.h 


Alternatively, you can copy them into the include directory of wxWidgets as follows.

$ cd include/wx
$ sudo cp *.h /usr/local/include/wx-3.0/wx/


An example wxWidgets program, wxjsontest.cpp, is shown below.

#include "wx/wx.h"

#include "wx/json_defs.h"
#include "wx/jsonreader.h"
#include "wx/jsonval.h"
#include "wx/jsonwriter.h"

class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};
class MyFrame : public wxFrame
{
public:
    MyFrame(const wxString& title);
    void OnQuit(wxCommandEvent& event);
    wxString ReadJson();
    wxTextCtrl *txt;
private:    
    wxDECLARE_EVENT_TABLE();
};

enum
{
    Minimal_Quit = wxID_EXIT
};

wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(Minimal_Quit,  MyFrame::OnQuit)
wxEND_EVENT_TABLE()

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{
    if ( !wxApp::OnInit() )
        return false;
    MyFrame *frame = new MyFrame("wxJson");
    frame->Show(true);
    return true;
}
MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title)
{
    wxMenu *fileMenu = new wxMenu;
    fileMenu->Append(Minimal_Quit, "E&xit\tAlt-X", "Quit this program");
    wxMenuBar *menuBar = new wxMenuBar();
    menuBar->Append(fileMenu, "&File");
    SetMenuBar(menuBar);
    wxString jresult = ReadJson();
    txt = new wxTextCtrl(this,wxID_ANY, jresult, wxDefaultPosition, wxDefaultSize,
        wxTE_MULTILINE | wxTE_RICH , wxDefaultValidator, wxTextCtrlNameStr);
}

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Close(true);
}

wxString MyFrame::ReadJson()
{
 // the JSON text, stored in a wxString object
 wxString document(("{\"Serial\" : {\"Baud\":9600, \"Parity\":\"Even\"}}"));
 wxString mes;

 // construct the JSON root object
 wxJSONValue  root;
 // construct a JSON parser
 wxJSONReader reader;

 // now read the JSON text and store it in the 'root' structure
 // check for errors before retreiving values...
 int numErrors = reader.Parse(document, &root);
    if (numErrors > 0) {
  mes = "ERROR: the JSON document is not well-formed";
     // const wxArrayString& errors = reader.GetErrors();
        return mes;
 }
 else {
  mes = "OK: Reading the JSON document... \n";
 }

 // get the values
 wxString v1 = root["Serial"]["Baud"].AsString();
 wxString v2 = root["Serial"]["Parity"].AsString();
 mes += "Serial: baudrate = "+ v1 + ", parity = " + v2;
    return mes;
}


You can use the following CMakeLists.txt file to compile it.

cmake_minimum_required(VERSION 2.8)
project( wxjsontest )
find_package(wxWidgets COMPONENTS core net base REQUIRED)
include("${wxWidgets_USE_FILE}")
include_directories(./wx)
add_executable( wxjsontest wxjsontest.cpp jsonreader.cpp jsonval.cpp jsonwriter.cpp )
target_link_libraries(${PROJECT_NAME} ${wxWidgets_LIBRARIES})


If you got ASSERTION failure warning issue in linking, you can comment out

// wxLogTrace( traceMask, _T("(%s) actual object: %s"), __PRETTY_FUNCTION__, GetInfo().c_str());


in jsonval.cpp in wxJSONValue::Item().

The more details about wxJson can be found at

http://wxcode.sourceforge.net/docs/wxjson/wxjson_tutorial.html [2]

References

[1] WikiBooks. JsonCpp. 2019.
url: https://en.wikibooks.org/wiki/JsonCpp.

[2] wxJSON - A brief tutorial
url: http://wxcode.sourceforge.net/docs/wxjson/wxjson_tutorial.html.

No comments:

Post a Comment

Comments are moderated and don't be surprised if your comment does not appear promptly.