This package provides the classes of a very simple JSON parser.

Introduction

JSON (JavaScript Object Notation) is a lightweight data-interchange format. Basically a JSON object is a comma separated list of pairs, enclosed in curly braces. A pair consists out of a label and a value, separated by a colon. E. g.:

{
    "name" : "Mike",
    "age" : 23,
    "hobbies" : [ "fishing", "rugby", "computer games" ]
}

The value can hold different kind of data, e. g. strings, numbers or even arrays. This seems very easy but can become rather complicated if a value is another JSON object: We have a recursive structure then, and a JSON object is best represented by a tree of nodes therefore.
Attention: All strings (and the labels) must be enclosed in quotes, all other types must not.
See www.json.org for details.

Parsing a JSON String and Traversing through the Parse Tree

To parse a JSON string and build the tree it must be given as a Java String to the constructor of the {@link JsonFse.JsonObj} class. Example:

        String s = "{" +
                       "\"name\" : \"Mike\"," +
                       "\"age\"  : 23,"       +
                       "\"hobbies\" : [ \"fishing\", \"rugby\", \"computer games\" ]" +
                   "}";
        try
        {
            JsonObj jo = new JsonObj(s);
            System.out.println(jo.getAsString());
        }
        catch (ParseErrorEx ex)
        {
            System.out.println(ex.getErrMsg());
        }

{@link JsonFse.JsonObj#getAsString} retranslates the tree recursively into a formatted string. If the original string could not be parsed because of an error a {@link JsonFse.ParseErrorEx} exception is thrown. {@link JsonFse.ParseErrorEx#getPos} delivers the index in the string where the error is detected.

To traverse through the JsonObj tree some knowledge of the node types is necessary. Their names reflect the names given in www.json.org. The abstract base class is {@link JsonFse.Node}, {@link JsonFse.NodePair} represents a pair, {@link JsonFse.NodeNumber} a number etc. To get pairs in a JSON object there are the methods {@link JsonFse.JsonObj#getNext} and {@link JsonFse.JsonObj#get}. The same methods are available in the {@link JsonFse.NodeArray} class. Example traversing through the JSON object jo created above:

         NodeString ns, nsa;
         NodeValue nv;
         NodePair np = jo.getNext();
         while (np != null)
         {
             ns = np.getString();
             System.out.println("label: " + ns.getAsString());
             nv = np.getValue();
             if (nv instanceof NodeArray)
             {
                 nsa = (NodeString)nv.get(1);
                 System.out.println("Second hobby of Mike: " + nsa.getAsString());
             }
             np = jo.getNext();
         }
         System.out.println("First pair in jo: " + jo.get(0).getAsString());

This produces the output:

label: "name"
label: "age"
label: "hobbies"
Second hobby of Mike: "rugby"
First pair in jo: "name" : "Mike"

As you can see it is easy to get a special value in a JSON object or of an array in it if you know the structure of the JSON object. If you do not know the structure you need to recognize it while traversing through the structure. Use the Java command instanceof to detect the type of unknown values as shown above.
Hint: There is no class NodeLabel, its name is {@link JsonFse.NodeString} instead, because of the wording in www.json.org.

Creating JSON Objects

It is possible to build up a JSON object by adding single pairs to it. The following code creates the same object as shown above:

         // Create an empty JSON object:
         JsonObj jo = new JsonObj();

         // Create the NodeArray:
         NodeArray na = new NodeArray();
         na.add(new NodeString("fishing"));
         na.add(new NodeString("rugby"));
         na.add(new NodeString("computer games"));

         // Add the pairs:
         jo.addPair("name", "Mike");
         jo.addPair("age", 23);
         jo.addPair("hobbies", na);

         System.out.println(jo.getAsString());

When creating NodeStrings or adding pairs containing strings it is not necessary to add the extra quotes around the strings; this is done by the constructor NodeString() automatically.

Grammar

The implementation is able to parse JSON objects according to this grammar, notated in EBNF:

object    = '{' , [ members ] , '}' ;
members   = pair , { ',' , pair } ;
pair      = string , ':' , value ;
string    = '"' , { char } , '"' ;
char      = ? any Unicode character ? - ctrlChar - '\') | ctrlChar | hexNumber ;
ctrlChar  = '\"' | '\\' | '\/' | '\b' | '\f' | '\n' | '\r' | '\t' ;
hexNumber = '\u' , hexDigit , hexDigit , hexDigit , hexDigit ;
hexDigit  = digit09 | hexChar ;
digit09   = digit0 | digit19 ;
digit0    = '0' ;
digit19   = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;
hexChar   = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' ;
value     = string | number | object | array | 'true' | 'false' | 'null' ;
number    = int | int frac | int exp | int , frac , exp ;
int       = [ '-' ] , digit | digit19 , digits ;
frac      = '.' , digits ;
exp       = eE , digits
digits    = digit09 , { digit09 } ;
eE        = 'e' | 'E' [ '+' | '-' ] ;
array     = '[' , [ elements ] , ']' ;
elements  = value , { ',' , value } ;

Reminder: The used symbols of the EBNF meta language are:

Symbol
Meaning
=
definition
,
concatenation
;
termination
|
alternation
[ ... ]
option
{ ... }
repetition
' ... '
terminal string
? ... ?
special sequence
-
exception

Class Diagram

The UML class diagram looks like this (sorry, Inkscape does not provide the correct end marker for the "uses" relationship; it should be "->" instead of "->>>"):

UML Class Diagram

@author Friedemann Seebass, Germany (www.friedemann-seebass.de) @version 1.0.0