Package JsonFse
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 JsonObj
class. Example: String s = "{" +
"\"name\" : \"Mike\"," +
"\"age\" : 23," +
"\"hobbies\" : [ \"fishing\", \"rugby\", \"computer games\" ]" +
"\"wife\"
: " +
"{
"
+
"\"name\" : \"Eve\"," +
"\"age\" :
21" +
"} " +
"}";
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. getErrPos()
delivers
the index in the string where the error is detected. This example
and the following can be found in JsonObj.main()
. 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(int)
. 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"
label: "wife"
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 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 mo = new
JsonObj();
// Create an empty
wife sub JSON object:
JsonObj wo = new
JsonObj();
// Create the hobby
NodeArray:
NodeArray na = new
NodeArray();
na.add(new
NodeString("fishing"));
na.add(new
NodeString("rugby"));
na.add(new
NodeString("computer games"));
// Add the pairs to
the wife JSON object:
wo.addPair("name", "Eve");
wo.addPair("age", 21);
// Putting all
togeteter and add the pairs to the Mike JSON object:
mo.addPair("name",
"Mike");
mo.addPair("age", 23);
mo.addPair("hobbies", na);
mo.addPair("wife", wo);
// Check the parsed tree:
System.out.println("A JSON
object constructed step by step:\n" + mo.getAsString());
When creating NodeString
s or adding pairs
containing strings it is not necessary to add the extra quotes
around the strings; this is done automatically.
Already parsed JSON objects can be reused by providing the
constructor of a new JsonObj
with the old root node:
// Make a copy of Eve's
sub JSON object and add her profession:
NodeObj no =
(NodeObj)mo.getValue("wife");
JsonObj eo = new
JsonObj(no);
eo.addPair("profession", "sales representative");
System.out.println("Mike's wife:\n" + eo.getAsString());
In the above example the new JsonObj
eo
is
created by initializing it with the wife's NodeObj
. Of
course it can modified then e. g. by adding a pair.
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:
Change Log
16 December 2018, V.1.1.0:
- New constructor
JsonObj(NodeObj)
and new methodJsonObj.setNodeObj(NodeObj)
are available; an already parsed JSON object can be reused without parsing its string again. - New constructor
NodePair(
String, int)
and new methodJsonObj.addPair(String, int)
to handle integer values.
1 July 2017, V.1.0.0:
- First published release.
28 December 2016, V.0.9.0:
- New method getAsInt() added.
- JUnit tests added.
- Version:
- 1.1.0
- Author:
- Friedemann Seebass, Germany (www.friedemann-seebass.de)
-
Class Summary Class Description JsonObj Represents a JSON object.JsonParser Simple JSON parser.Node Base class of all nodes a JSON tree consists of.NodeArray Node representing an array of values.NodeElements Holds the elements of a NodeArray.NodeFalse Represents the terminal symbol "false".NodeMembers This node class represents the members (i. e. the pairs) of a JSON object.NodeNull Represents the terminal symbol "null".NodeNumber Represents a number in a JSON object.NodeObj Represents a whole JSON object, i. e. its members, i. e. a list of pairs consisting out of a label and a value.NodePair Represents a pair consisting of a label and a value.NodeString Represents a JSON String.NodeTrue Represents the terminal symbol "true".NodeValue This class represents a JSON value. -
Exception Summary Exception Description ParseErrorEx This exception is thrown when the JSON parser detects a parse error.