Code archives/File Utilities/tiny JSON reader/writer
This code has been declared by its author to be Public Domain code.
Download source code
| from http://www.json.org : 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. This is a tiny JSON library I wrote in about an hour and a half. Amazingly, it worked first time! |
Type jsondecoder Field txt$ Field i Field curchr$ Field things:TList Method New() things=New TList End Method Method getnext(tokens$[],onlywhitespace=1) oldi=i While i<Len(txt) c$=Chr(txt[i]) i:+1 For token$=EachIn tokens If c=token curchr=c Return 1 EndIf Next If onlywhitespace And (Not (c=" " Or c="~t" Or c="~n" Or c="~r")) i:-1 Return 0 EndIf Wend i=oldi Return 0 End Method Function Create:jsondecoder(txt$) j:jsondecoder=New jsondecoder j.txt=txt j.i=i Return j End Function Method parse() While getnext(["{","["]) Select curchr Case "{" 'new object o:jsonobject=parseobject() If Not o Print "error - couldn't parse object" EndIf things.addlast o Case "[" 'new array a:jsonarray=parsearray() If Not a Print "error - couldn't parse array" EndIf things.addlast a End Select Wend End Method Method parseobject:jsonobject() o:jsonobject=New jsonobject While getnext(["~q","}"]) Select curchr Case "~q" p:jsonpair=parsepair() If Not p Print "error reading pair" EndIf o.pairs.addlast p If Not getnext([",","}"]) Print "error after reading pair - expected either , or }" EndIf If curchr="}" Return o EndIf Case "}" Return o End Select Wend Print "error reading Object - expected a } at least!" End Method Method parsepair:jsonpair() p:jsonpair=New jsonpair p.name=parsestring() If Not getnext([":"]) Print "error reading pair - expected a :" EndIf v:jsonvalue=parsevalue() If Not v Print "error reading pair - couldn't read a value" EndIf p.value=v Return p End Method Method parsearray:jsonarray() a:jsonarray=New jsonarray While getnext(["~q","-","0","1","2","3","4","5","6","7","8","9","{","[","t","f","n","]"]) Select curchr Case "~q","-","0","1","2","3","4","5","6","7","8","9","{","[","t","f","n" i:-1 v:jsonvalue=parsevalue() a.values.addlast v If Not getnext([",","]"]) Print "error - expecting , or ]" EndIf If curchr="]" Return a EndIf Case "]" Return a End Select Wend Print "error - expecting a value or ]" End Method Method parsestring$() oldi=i s$="" While getnext(["~q","\"],0) s:+txt[oldi..i-1] Select curchr Case "~q" Return s Case "\" Select Chr(txt[i]) Case "~q" s:+"~q" Case "\" s:+"\" Case "/" s:+"/" Case "b" s:+Chr(8) Case "f" s:+Chr(12) Case "n" s:+"~n" Case "r" s:+"~r" Case "t" s:+"~t" Case "u" s:+parseunicode() End Select i:+1 End Select oldi=i Wend End Method Method parseunicode$() n:Short=0 For t=1 To 4 n:*16 c=txt[i+t] If c>48 And c<57 n:+c-48 ElseIf c>=65 And c<=70 n:+c-55 ElseIf c>=97 And c<=102 n:+c-87 EndIf Next i:+4 Return Chr(n) End Method Method parsevalue:jsonvalue() If Not getnext(["~q","-","0","1","2","3","4","5","6","7","8","9","{","[","t","f","n"]) Print "error - expecting the beginning of a value" EndIf Select curchr Case "~q" s$=parsestring() Return jsonstringvalue.Create(s,0) Case "-","0","1","2","3","4","5","6","7","8","9" n:Double=parsenumber() Return jsonnumbervalue.Create(n) Case "{" o:jsonobject=parseobject() Return o Case "[" a:jsonarray=parsearray() Return a Case "t" i:+3 Return jsonliteralvalue.Create(1) Case "f" i:+4 Return jsonliteralvalue.Create(0) Case "n" i:+2 Return jsonliteralvalue.Create(-1) End Select End Method Method parsenumber:Double() i:-1 sign=1 n:Double=0 Select Chr(txt[i]) Case "-" i:+2 Return parsenumber()*(-1) Case "0" i:+1 If getnext(["."]) n=parsefraction() EndIf Case "1","2","3","4","5","6","7","8","9" n=parseinteger() If getnext(["."]) n:+parsefraction() EndIf End Select If Chr(txt[i])="e" Or Chr(txt[i])="E" i:+1 Select Chr(txt[i]) Case "+" sign=1 Case "-" sign=-1 Default Print "error - not a + or - when reading exponent in number" End Select e=parseinteger() n:*10^(sign*e) EndIf Print "parsed number "+String(n) Return n End Method Method parsefraction:Double() digits=0 n:Double=0 While txt[i]>=48 And txt[i]<=57 And i<Len(txt) n:*10 n:+txt[i]-48 i:+1 digits:+1 Wend n:/(10^digits) If i=Len(txt) Print "error - reached EOF while reading number" EndIf Print "parsed fraction "+String(n) Return n End Method Method parseinteger:Double() n:Double=0 While txt[i]>=48 And txt[i]<=57 And i<Len(txt) n:*10 n:+txt[i]-48 i:+1 Wend If i=Len(txt) Print "error - reached EOF while reading number" EndIf Print "parsed integer "+String(n) Return n End Method End Type Type jsonvalue Method repr$(tabs$="") Return tabs End Method End Type Type jsonobject Extends jsonvalue Field pairs:TList Method New() pairs=New TList End Method Method addnewpair(txt$,value:jsonvalue) pairs.addlast jsonpair.Create(txt,value) End Method Method repr$(tabs$="") t$="{" ntabs$=tabs+"~t" op:jsonpair=Null For p:jsonpair=EachIn pairs If op Then t:+"," t:+"~n"+ntabs+p.repr(ntabs) op=p Next t:+"~n"+tabs+"}" Return t End Method Method getvalue:jsonvalue(name$) For p:jsonpair=EachIn pairs If p.name=name Return p.value EndIf Next End Method Method getstringvalue$(name$) v:jsonstringvalue=jsonstringvalue(getvalue(name)) If v Return v.txt EndIf End Method Method getnumbervalue:Double(name$) v:jsonnumbervalue=jsonnumbervalue(getvalue(name)) If v Return v.number EndIf End Method Method getliteralvalue(name$) v:jsonliteralvalue=jsonliteralvalue(getvalue(name)) If v Return v.value EndIf End Method Method getarrayvalue:jsonarray(name$) v:jsonarray=jsonarray(getvalue(name)) Return v End Method Method getobjectvalue:jsonobject(name$) v:jsonobject=jsonobject(getvalue(name)) Return v End Method End Type Type jsonpair Field name$,value:jsonvalue Function Create:jsonpair(name$,value:jsonvalue) p:jsonpair=New jsonpair p.name=name p.value=value Return p End Function Method repr$(tabs$="") t$="~q"+name+"~q : " For i=1 To (Len(t)+7)/8 tabs:+"~t" Next middo$="" For i=1 To (8-(Len(t) Mod 8)) middo:+" " Next Return t+middo+value.repr(tabs) End Method End Type Type jsonarray Extends jsonvalue Field values:TList Method New() values=New TList End Method Method repr$(tabs$="") t$="[" ntabs$=tabs+"~t" ov:jsonvalue=Null For v:jsonvalue=EachIn values If ov Then t:+"," t:+"~n"+ntabs+v.repr(ntabs) ov=v Next t:+"~n"+tabs+"]" Return t End Method End Type Type jsonstringvalue Extends jsonvalue Field txt$ Function Create:jsonstringvalue(txt$,pretty=1) jsv:jsonstringvalue=New jsonstringvalue If pretty otxt$="" i=0 For i=0 To Len(txt)-1 Select Chr(txt[i]) Case "~q" otxt:+"\~q" Case "\" otxt:+"\\" Case "/" otxt:+"\/" Case Chr(8) otxt:+"\b" Case Chr(12) otxt:+"\f" Case "~n" otxt:+"\n" Case "~r" otxt:+"\r" Case "~t" otxt:+"\t" Default otxt:+Chr(txt[i]) End Select Next jsv.txt=otxt Else jsv.txt=txt EndIf Return jsv End Function Method repr$(tabs$="") Return "~q"+txt+"~q" End Method End Type Type jsonnumbervalue Extends jsonvalue Field number:Double Function Create:jsonnumbervalue(n:Double) jnv:jsonnumbervalue=New jsonnumbervalue jnv.number=n Return jnv End Function Method repr$(tabs$="") Return String(number) End Method End Type Type jsonliteralvalue Extends jsonvalue Field value '1 - true '0 - false '-1 - nil Function Create:jsonliteralvalue(value) jlv:jsonliteralvalue=New jsonliteralvalue jlv.value=value Return jlv End Function Method repr$(tabs$="") Select value Case 1 Return "true" Case 0 Return "false" Case -1 Return "nil" End Select End Method End Type 'EXAMPLE f:TStream=ReadFile("json.txt") txt$="" While Not Eof(f) txt:+f.ReadLine() Wend j:jsondecoder=jsondecoder.Create(txt) j.parse() For v:jsonvalue=EachIn j.things Print v.repr() Next |