deutsche version  English version
A Recursive Java Parser for JSON Strings
Software

JSON Parser

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. All strings (and the labels) must be enclosed in quotes, all other types must not. See www.json.org for details.

Features

The JSON parser comes as the Java library JsonFse in a JAR file. It is a simple implementation which accepts only Java Strings as input. I have needed the parser for my Camera RC project, and I did not like to familiarize myself with other JSON libraries. And to write a recursive parser after some years again promised fun!
  • The parser analyses the input string, i. e. build the parse tree and put each recognized leaf into the tree.
  • The parser detects syntactical errors in the string and shows the position of the error.
  • You can traverse through the tree and get single elements of it.
  • You can build or modify a tree by adding single elements.
  • There is a full documentation in Java Doc format.
  • The library is open source (LGPL).
For own enhancements you can download the complete Netbeans project containing JUnit test routines.

Examples

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

import JsonFse.*;
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());
}

JsonObj.getAsString() retranslates the tree recursively into a formatted string. If the original string could not be parsed because of an error a ParseErrorEx exception is thrown. ParseErrorEx.getErrPos() delivers the index in the string where the error is detected, ParseErrorEx.getErrMsg() gets a complete error message.

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 Node, NodePair represents a pair, NodeNumber a number etc. To get pairs in a JSON object there are the methods JsonObj.getNext() and JsonObj.get(). The same methods are available in the 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.

To see how to create a JSON object and for further details have a look at the library's documentation.

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:

SymbolMeaning
=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

Download

File
SizeDescriptionVersionPlatform
JsonFse_100.zip 207 kB JSON parser library 1.0.0 JRE 1.8.0 or newer
JsonFse_src_100.zip
95 kB JSON parser library source code (Netbeans project) 1.0.0 Netbeans IDE 8.1

Change Log

1 July 2017, V.1.0.0:
  • First published release.
28 December 2016, V.0.9.0:
  • New method getAsInt() added.
  • JUnit tests added.

Links