Preface
Here is a fourth part of wxJSON tutorial provided by Luciano Cattani, author and maintainer of wxJSON library.
- Visit wxJSON homepage
- Read Part I of this tutorial
- Read Part II of this tutorial
- Read Part III of this tutorial
- Read Part IV of this tutorial
Using Comment Lines in wxJSON
Comments are not supported by the JSON syntax specifications but many JSON implementations do recognize and store comment lines in the JSON value objects. Starting by version 0.2, the wxJSON library do recognize and store C/C++ comment lines in the JSON input text and can also write comments to the JSON output text.
Why should we use comments in JSON formatted text?
There are several reasons: in an application’s configuration file like the one we have seen in Example 2: a configuration file comments are very usefull to help the user to understand the meaning of each configuration option.
On the other hand, if a data structure is sent over a network connection, it is most likely that comments are not really needed but they may still be usefull for debugging purposes or for explaining the value, as in the following example:
{ "Person" : { { "Name" : "John Smith", "Height" : 190, // expressed in centimeters "Birthday" : { "Year" : 1965, "Month" : 8, "Day" : 18 } } }
Adding comments to JSON values
The wxJSONValue
class defines some functions for adding and retrieving comment lines in a JSON value. The function for adding comments is the wxJSONValue::AddComment()
function which takes two parameters:
- the string that has to be added as comment
- the position of the comment line when the value is written to JSON text
The possible values for the position
parameter are:
wxJSONVALUE_COMMENT_BEFORE
: the comment will be written before the value it refers towxJSONVALUE_COMMENT_AFTER
: the comment will be written after the value it refers towxJSONVALUE_COMMENT_INLINE
: the comment will be written on the same line as the value it refers to
Here is an example:
{ // comment before 'key-1' "key-1" : "value-1", "key-2" : "value-2", // comment inline 'key-2' "key-3" : "value-3" // comment after 'key-3' }
To get the above output use the following code fragment:
wxJSONValue root; root["key-1"] = "value-1"; root["key-2"] = "value-2"; root["key-3"] = "value-3"; root["key-1"].AddComment( "// comment before", wxJSONVALUE_COMMENT_BEFORE ); root["key-2"].AddComment( "// comment inline", wxJSONVALUE_COMMENT_INLINE ); root["key-3"].AddComment( "// comment after", wxJSONVALUE_COMMENT_AFTER );
You have to note that comment lines are kept as an array of strings in a data member of the wxJSONValue
object: this means that you can add more than one comment line to a JSON value object but remember that there is only one data member for storing the position of all comment lines. In other words, the position at which the comment lines are written in the JSON output text in the same position as the one specified in the last call to the wxJSONValue::AddComment
function.
In order to prevent that the comment’s position have to be set in the last call to the AddComment()
function, you can specify the wxJSONVALUE_COMMENT_DEFAULT
constant as the position parameter. This constant causes the function to not modify the actual position value. If you use this constant in the first call to the AddComment()
function, it is interpreted as wxJSONVALUE_COMMENT_BEFORE
. Below you find an example:
wxJSONValue root; root.AddComment( "// comment for root (line 1)", wxJSONVALUE_COMMENT_BEFORE ); // no need to specify the comment position in subsequent calls to AddComment() // the old position is not modified root.AddComment( "// comment for root (line 2)" ); // set the value for 'key-1' root["key-1"] = "value1"; // now we add a comment line for 'key-1'. We do not specify the comment // position so it defaults to wxJSONVALUE_COMMENT_DEFAULT which cause // the AddCommnen() function to maintan the old position. // As the comment position was never set before, the wxJSONVALUE_COMMENT_BEFORE // will be set root["key-1"].AddComment( "// comment before key-1" ); // set the value of 'key-4' an an empty object. // note that we cannot use the default wxJSONValue constructor to get an // empty object type: the default ctor constructs a NULL value object. root["key-4"] = wxJSONValue( wxJSONTYPE_OBJECT ); // now we add an inline comment to 'key-4' root["key-4"].AddComment( "// comment inline key-4", wxJSONVALUE_COMMENT_BEFORE ); // now we write the JSON 'root' value to a JSON formatted string // object. Note that we have to specify some flags in the wxJSONWriter // constructor wxJSONWriter writer( wxJSONWRITER_STYLED | wxJSONWRITER_WRITE_COMMENTS ); wxString jsonText; writer.Write( root, jsonText );
Below is the output text:
// comment for root (line 1) // comment for root (line 2) { // comment before 'key2' "key-1" : "value1", "key-4" : { // comment inline key-4 } }
Adding inline comments
You should be carefull when adding inline comments. Comment lines are stored in an array of string, thus allowing to have more than one line of comments. This is good for comments that apear before or after the value they refer to but for inline comments, the output is not easy to read. Look at the following example:
wxJSONValue root; root["key-1"] = "value1"; root["key-1"].AddComment( " // comment inline (1)", wxJSONVALUE_COMMENT_INLINE ); root["key-1"].AddComment( " // comment inline (2)" ); root["key-1"].AddComment( " // comment inline (3)" ); // this is the JSON formatted output: { "key-1" : "value1", // comment inline (1) // comment inline (2) // comment inline (3) }
Note that only the first line is really printed inline. The other two lines are printed after the value they refer to and without indentation: this is not very readable. For this reason, you should use inline comments only when you have only one line of comments. If you need more than one line of comment use the before or the after comment’s position.
Syntax checks for comment lines
The wxJSONValue::AddComment()
function checks that the string that you are adding as a comment to the JSONvalue object is a correct C/C++ comment. In other words, if you want to add a C++ comment string, the string passed as a parameter to the wxJSONValue::AddComment()
function must start with two slash characters and must end with a LF. If the LF character is missing, the function adds it for you. The following code fragment shows some examples:
wxJSONValue v1( 10 ); v1.AddComment( "// A C++ comment line\n" ); // this is OK v1.AddComment( "// Another C++ comment line" ); // this is OK v1.AddComment( "/* A C-style comment */"); // OK wxJSONValue v2( 20 ); v2.AddComment( "A C++ comment line\n" ); // Error: does not start with '//' v2.AddComment( "/ A C++ comment line\n" ); // Error: does not start with '//' v2.AddComment( "/*** comment **" ); // Error: the close-comment is missing // the following is OK: new-line characters may follow // the end-comment characters of a C-style comment wxJSONValue v3( 30 ); v2.AddComment( "/*** C comment ***/\n\n\n" );
Note that the function cannot trap all possible errors because the checks that are done by the function are very simple:
- for C++ comments checks that the string starts with two slash characters and ends with a LF char: the LF har is automatically added if it is missing
- for C-style comments check that the string start with the slash-asterisk character couple and ends with the asterisk-slash caracters (trailing LF chars are permitted)
Note that the following examples are considered OK by the function but if you add those strings to some values and write them to a JSON text stream you end up with a incorrect JSON text.
// the following is not correct: the AddComment() function only // appends the final LF char wxJSONValue v1( 10 ); v1.AddComment( "// Line 1\nLine2" ); // this is the JSON output (it is not OK) ... // Line 1 Line 2 10 ...
You would have to write:
wxJSONValue v1( 10 ); v1.AddComment( "// Line 1" ); v1.AddComment( "// Line 2" );
Nested C-style comments are not handled correctly by the wxJSON parser:
wxJSONValue v2( 20 ); v2.AddComment( "/* comment1 /* comment2 */ */" ); // this is the JSON text output: ... /* comment1 /* comment2 */ */ 20 ...
The parser will report an error when it reads the last close-comment characters because when a C-style comment starts, all characters until the first close-comment chars are ignored by the parser.
Reading comment lines from JSON text
As already written above, comment lines are a wxJSON extension to the JSON format specification. Comments may be directly added to wxJSONValue
objects using memberfunctions or they can be stored in the values when a JSON formatted text input is read by the parser. Note that by default the wxJSONReader
class recognizes C/C++ comments in the input text but simply ignores them: if you wanr to store the comments in the value they refer to you have to pass some flags to the parser’s constructor:
// this ctor is error tolerant and stores comments wxJSONReader reader1( wxJSONREADER_TOLERANT | wxJSONREADER_STORE_COMMENTS ); // this ctor is not error tolerant: wxJSON extensions are off wxJSONReader reader2( wxJSONREADER_STRICT ); // this ctor is error tolerant but does not store comments wxJSONReader reader3; // this ctor recognizes all wxJSON extensions except the // 'multiline string' feature which is reported as an error // the parser also stores comments wxJSONReader reader1( wxJSONREADER_ALLOW_COMMENTS | wxJSONREADER_CASE | wxJSONREADER_MISSING | wxJSONREADER_STORE_COMMENTS ); // parser is tolerant and stores comments but comments apear AFTER // the value they refer to wxJSONReader reader1( wxJSONREADER_TOLERANT | wxJSONREADER_STORE_COMMENTS ); | wxJSONREADER_COMMENTS_AFTER );
See the wxJSONReader
class’s description for more informations about the wxJSON parser’s extensions. Also note that comment’s related constructor’s flags are only meaningfull if the main flags are also specified. In other words, the wxJSONREADER_STORE_COMMENTS
flag is only meaningfull if wxJSONREADER_ALLOW_COMMENTS
is also set (or the wxJSONREADER_TOLERANT
constant which includes it). Moreover the wxJSONREADER_COMMENTS_AFTER
is only meaningfull if wxJSONREADER_STORE_COMMENTS
is also set: if comments are not stored, there is no need for the parser to know the position of the comments with respect to the value.
Below you find a JSON text with many comment lines and the description of which value the comments refer to. The parser is constructed with the wxJSONREADER_STORE_COMMENT
flag set.
// comment for root (line 1) // comment for root (line 2) { "key-1" : "value1", // comment before 'key2' "key-2" : "value2", // comment before 'key3' (1) // comment before 'key3' (2) "key-3" : { "key3-1" : "value3-1", // comment before key3-2 "key3-2" : "value3-2" }, "key-4" : { // comment inline key4 // this comment does not refer to anything } "key-5" : [ // comment inline key5 // comment before item 5-1 "item5-1", "item5-2", // comment inline 5-2 "item5-3" // comment inline 5-3 // this comment does not refer to anything ], "key-6" : // comment inline key-6 "value", "key-7" : { "key-7-1" : "value-7-1" }, // comment inline key-7 "key-8" // comment inline key-8(1) : // comment inline key-8(2) "value", // comment inline key-8(3) "key-9" : { "key9-1" : 91, "key9-2" : 92 } "key-10" : [ ] // comment inline key-10 // this comment does not refer to anything } // this comment does not refer to anything // if COMMENT_BEFORE. This non-JSON text is ignored by the parser because it apears after the top-level close-object character