wxJSON Tutorial – Part I – Introduction

Preface

Today I start publishing a cycle of articles related to wxJSON library. These articles are provided by Luciano Cattani, author and maintainer of wxJSON.

Below is a first article which will give you a brief description of what wxJSON is, how it can help you in your work and how it can make development of wxWidgets applications easier.

Visit wxJSON homepage

Introduction

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition – December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.

JSON is a text format and it is completely platform-independent. You do not need to worry about computer’s architecture, endianness or operating system. It is very easy for humans to read and write and easy for machines to parse and generate. It is also light-weight and much more compact than other data-interchange formats.

We will learn how to use the wxJSON library by examining some simple examples. JSON is a data format; it is not suitable for describing complex documents or to store images, audio and video streams. For these purposes, there are many other formats which are by far more appropriate than JSON.
If you are new to JSON it is better than you first read the following pages, which describes the JSON syntax, its advantages and its disadvantages:

Example 1: a simple example

Let’s look an example on how to read and write JSON data using the wxWidgets implementation of the JSON value class. Suppose we have the following text stored in a wxString object (but you can also read it from a stream class):

 /***************************
  This is a C-style comment
 ***************************/
 {
   // this is a comment line in C++ style
   "wxWidgets" :
   {
     "Description" : "Cross-platform GUI framework",
     "License" : "wxWidgets",
     "Version" :
     {
       "Major" : 2,
       "Minor" : 8,
       "Stable" : true
     },
     "Languages" :
     [
       "C++",
       "Phyton",
       "Perl",
       "C#/Net"
     ]
   }
 }

We can retrieve the values using several access methods as explained in the following code fragment:

// the JSON text, stored in a wxString object
  wxString document( _T( "/************n  This is a ...... "));

  // 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 )  {
    cout < < "ERROR: the JSON document is not well-formed" << endl;
    const wxArrayString& errors = reader.GetErrors();
    // now print the errors array
    ...
    return;
  }

  // get the 'License' value
  wxString license  = root["wxWidgets"]["License"].AsString();

  // check if a 'Version' value is present
  bool hasMember = root["wxWidgets"].HasMember( "Version" );

  // get the major version value as an integer
  int majorVer = root["wxWidgets"]["Version"]["Major"].AsInt();

  // get the minor version; if the value does not exists, the
  // default value of ZERO is returned
  wxJSONValue defaultValue( 0 );
  int minorVer = root["wxWidgets"]["Version"].Get( "Minor", defaultValue).AsInt();

  // the same as above, but directly constructing the default value
  int minorVer = root["wxWidgets"]["Version"].Get( "Minor", wxJSONValue( 0)).AsInt();

  // now retrive the array of supported languages
  wxJSONValue languages = root["wxWidgets"]["Languages"];

  // before obtaining the array of strings, we check that the type
  // of the 'language' object is an array
  // NOTE: this is not strictly necessary.
  bool isArray = languages.IsArray();

  wxArrayString supportedLanguages;
  for ( int i = 0; i < languages.Size() i++ ) {
    supportedLanguages.Add( languages[i].AsString());
  }

  // finally, we get an array of all member's names of the 'wxWidgets'
  // item. The array will contain (maybe not in this order):
  // 
  //   Description
  //   License
  //   Version
  //   Languages
  //
  wxArrayString memberNames = root["wxWidgets"].GetMemberNames();
[/sourcecode]
The wxJSONReader class's constructor has some parameters that control how much error-tolerant should the parser be. By default, the parser is very tolerant about non fatal errors which are reported as warnings. For more information see the wxJSONReader class's description.

Adding new values or changing the value of existing JSON-value objects is also very simple. The following code fragment shows some examples:

 // upgrade the minor version
  root["wxWidgets"]["Version"]["Minor"] = 9;

  // create the new 'URL' item
  root["wxWidgets"]["URL"] = "http://www.wxwidgets.org";

  // append a new supported language in the 'Language' array
  root["wxWidgets"]["Languages"].Append( "Java" );

  // creates the new 'Authors' array.
  // creating an array is just as simple as using the 'Append()'
  // member function.
  root["wxWidgets"]["Authors"].Append( "J. Smart" );
  root["wxWidgets"]["Authors"].Append( "V. Zeitling" );
  root["wxWidgets"]["Authors"].Append( "R. Roebling" );
  ... and many others...

  // you can also use subscripts to obtain the same result:
  root["wxWidgets"]["Authors"][0] = "J. Smart";
  root["wxWidgets"]["Authors"][1] = "V. Zeitling";
  root["wxWidgets"]["Authors"][2] = "R. Roebling";
  ... and many others...

  // after the changes, we have to write the JSON object back
  // to its text representation
  wxJSONWriter writer;
  wxString     str;
  writer.Write( root, str );

  // if you use the default writer constructor the JSON text
  // output is human-readable (indented) but does not contain
  // the comment lines
  // if you want to keep the comment lines you have to pass
  // some parameters to the wxJSONWriter constructor
  wxJSONWriter writer2( wxJSONWRITER_STYLED | wxJSONWRITER_WRITE_COMMENTS );
  wxString     str2;
  writer2.Write( root, str2 );

The writer class’s constructor has some parameters that allow you to control the style of the output. By default, the writer produces human-readable output with a three-space indentation for objects / arrays sub-items (as shown in the example text above) but it does not write comment lines. You can suppress indentation if, for example, the JSON text has to be sent over a network connection.

Also note that in order to actually have comment lines written back to the JSON text document, you also have to store comments when reading the JSON text document. By default, the parser is error-tolerant and recognizes C/C++ comments but it does not store them in the value they refer to. This means that you cannot rewrite them back regardless the flags used in the writer class. To know more about comment lines in JSONvalue objects, see Using comment lines in wxJSON.

The power and simplicity of JSON

I do not know much about XML but I think that JSON is really a valid alternative to it if you just need a simple format for data interchange. JSON is not suitable for describing complex documents: it can only handle data and it is specialized in handling progamming language’s variables.

I only would like to let you know how much simple is wxJSON: the subscript operators used to access JSON values returns a reference to the JSON value itself thus allowing to have multiple subscripts. Moreover, if the accessed value does not exists, it will be created and a reference to the newly created value is returned. This feature lets you use constructs such as the following:

wxJSONValue value;
value["key-1"]["key-2"]["key-3"][4] = 12;

Because value does not contain any of the specified keys (for objects) and elements (for the array), they will be created. The JSON output of the code fragment seen above is as follows:

{
    "key-1" :  {
       "key-2" :  {
          "key-3" : [
             null,
             null,
             null,
             null,
             12
          ]
        }
     }
  }

Leave a Reply

Your email address will not be published. Required fields are marked *

Please leave these two fields as-is: