' VBJSON is a VB6 adaptation of the VBA JSON project at http://code.google.com/p/vba-json/ ' Some bugs fixed, speed improvements added for VB6 by Michael Glaser (vbjson@ediy.co.nz) ' BSD Licensed ‘cJSONScript Option Explicit Const INVALID_JSON As Long = 1 Const INVALID_OBJECT As Long = 2 Const INVALID_ARRAY As Long = 3 Const INVALID_BOOLEAN As Long = 4 Const INVALID_NULL As Long = 5 Const INVALID_KEY As Long = 6 Const INVALID_RPC_CALL As Long = 7 Private psErrors As String Public Function GetParserErrors() As String GetParserErrors = psErrors End Function Public Function ClearParserErrors() As String psErrors = "" End Function ' ' parse string and create JSON object ' Public Function parse(ByRef str As String) As Object Dim index As Long index = 1 psErrors = "" On Error Resume Next Call skipChar(str, index) Select Case Mid(str, index, 1) Case "{" Set parse = parseObject(str, index) Case "[" Set parse = parseArray(str, index) Case Else psErrors = "Invalid JSON" End Select End Function ' ' parse collection of key/value ' Private Function parseObject(ByRef str As String, ByRef index As Long) As Dictionary Set parseObject = New Dictionary Dim sKey As String ' "{" Call skipChar(str, index) If Mid(str, index, 1) <> "{" Then psErrors = psErrors & "Invalid Object at position " & index & " : " & Mid(str, index) & vbCrLf Exit Function End If index = index + 1 Do Call skipChar(str, index) If "}" = Mid(str, index, 1) Then index = index + 1 Exit Do ElseIf "," = Mid(str, index, 1) Then index = index + 1 Call skipChar(str, index) ElseIf index > Len(str) Then psErrors = psErrors & "Missing '}': " & Right(str, 20) & vbCrLf Exit Do End If ' add key/value pair sKey = parseKey(str, index) On Error Resume Next parseObject.Add sKey, parseValue(str, index) If Err.Number <> 0 Then psErrors = psErrors & Err.Description & ": " & sKey & vbCrLf Exit Do End If Loop eh: End Function ' ' parse list ' Private Function parseArray(ByRef str As String, ByRef index As Long) As Collection Set parseArray = New Collection ' "[" Call skipChar(str, index) If Mid(str, index, 1) <> "[" Then psErrors = psErrors & "Invalid Array at position " & index & " : " + Mid(str, index, 20) & vbCrLf Exit Function End If index = index + 1 Do Call skipChar(str, index) If "]" = Mid(str, index, 1) Then index = index + 1 Exit Do ElseIf "," = Mid(str, index, 1) Then index = index + 1 Call skipChar(str, index) ElseIf index > Len(str) Then psErrors = psErrors & "Missing ']': " & Right(str, 20) & vbCrLf Exit Do End If ' add value On Error Resume Next parseArray.Add parseValue(str, index) If Err.Number <> 0 Then psErrors = psErrors & Err.Description & ": " & Mid(str, index, 20) & vbCrLf Exit Do End If Loop End Function ' ' parse string / number / object / array / true / false / null ' Private Function parseValue(ByRef str As String, ByRef index As Long) Call skipChar(str, index) Select Case Mid(str, index, 1) Case "{" Set parseValue = parseObject(str, index) Case "[" Set parseValue = parseArray(str, index) Case """", "'" parseValue = parseString(str, index) Case "t", "f" parseValue = parseBoolean(str, index) Case "n" parseValue = parseNull(str, index) Case Else parseValue = parseNumber(str, index) End Select End Function ' ' parse string ' Private Function parseString(ByRef str As String, ByRef index As Long) As String Dim quote As String Dim Char As String Dim Code As String Dim SB As New cStringBuilder Call skipChar(str, index) quote = Mid(str, index, 1) index = index + 1 Do While index > 0 And index <= Len(str) Char = Mid(str, index, 1) Select Case (Char) Case "\" index = index + 1 Char = Mid(str, index, 1) Select Case (Char) Case """", "\", "/", "'" SB.Append Char index = index + 1 Case "b" SB.Append vbBack index = index + 1 Case "f" SB.Append vbFormFeed index = index + 1 Case "n" SB.Append vbLf index = index + 1 Case "r" SB.Append vbCr index = index + 1 Case "t" SB.Append vbTab index = index + 1 Case "u" index = index + 1 Code = Mid(str, index, 4) SB.Append ChrW(Val("&h" + Code)) index = index + 4 End Select Case quote index = index + 1 parseString = SB.toString Set SB = Nothing Exit Function Case Else SB.Append Char index = index + 1 End Select Loop parseString = SB.toString Set SB = Nothing End Function ' ' parse number ' Private Function parseNumber(ByRef str As String, ByRef index As Long) Dim Value As String Dim Char As String Call skipChar(str, index) Do While index > 0 And index <= Len(str) Char = Mid(str, index, 1) If InStr("+-0123456789.eE", Char) Then Value = Value & Char index = index + 1 Else parseNumber = CDec(Value) Exit Function End If Loop End Function ' ' parse true / false ' Private Function parseBoolean(ByRef str As String, ByRef index As Long) As Boolean Call skipChar(str, index) If Mid(str, index, 4) = "true" Then parseBoolean = True index = index + 4 ElseIf Mid(str, index, 5) = "false" Then parseBoolean = False index = index + 5 Else psErrors = psErrors & "Invalid Boolean at position " & index & " : " & Mid(str, index) & vbCrLf End If End Function ' ' parse null ' Private Function parseNull(ByRef str As String, ByRef index As Long) Call skipChar(str, index) If Mid(str, index, 4) = "null" Then parseNull = Null index = index + 4 Else psErrors = psErrors & "Invalid null value at position " & index & " : " & Mid(str, index) & vbCrLf End If End Function Private Function parseKey(ByRef str As String, ByRef index As Long) As String Dim dquote As Boolean Dim squote As Boolean Dim Char As String Call skipChar(str, index) Do While index > 0 And index <= Len(str) Char = Mid(str, index, 1) Select Case (Char) Case """" dquote = Not dquote index = index + 1 If Not dquote Then Call skipChar(str, index) If Mid(str, index, 1) <> ":" Then psErrors = psErrors & "Invalid Key at position " & index & " : " & parseKey & vbCrLf Exit Do End If End If Case "'" squote = Not squote index = index + 1 If Not squote Then Call skipChar(str, index) If Mid(str, index, 1) <> ":" Then psErrors = psErrors & "Invalid Key at position " & index & " : " & parseKey & vbCrLf Exit Do End If End If Case ":" index = index + 1 If Not dquote And Not squote Then Exit Do Else parseKey = parseKey & Char End If Case Else If InStr(vbCrLf & vbCr & vbLf & vbTab & " ", Char) Then Else parseKey = parseKey & Char End If index = index + 1 End Select Loop End Function ' ' skip special character ' Private Sub skipChar(ByRef str As String, ByRef index As Long) Dim bComment As Boolean Dim bStartComment As Boolean Dim bLongComment As Boolean Do While index > 0 And index <= Len(str) Select Case Mid(str, index, 1) Case vbCr, vbLf If Not bLongComment Then bStartComment = False bComment = False End If Case vbTab, " ", "(", ")" Case "/" If Not bLongComment Then If bStartComment Then bStartComment = False bComment = True Else bStartComment = True bComment = False bLongComment = False End If Else If bStartComment Then bLongComment = False bStartComment = False bComment = False End If End If Case "*" If bStartComment Then bStartComment = False bComment = True bLongComment = True Else bStartComment = True End If Case Else If Not bComment Then Exit Do End If End Select index = index + 1 Loop End Sub Public Function toString(ByRef obj As Variant) As String Dim SB As New cStringBuilder Select Case VarType(obj) Case vbNull SB.Append "null" Case vbDate SB.Append """" & CStr(obj) & """" Case vbString SB.Append """" & Encode(obj) & """" Case vbObject Dim bFI As Boolean Dim i As Long bFI = True If TypeName(obj) = "Dictionary" Then SB.Append "{" Dim keys keys = obj.keys For i = 0 To obj.Count - 1 If bFI Then bFI = False Else SB.Append "," Dim key key = keys(i) SB.Append """" & key & """:" & toString(obj.item(key)) Next i SB.Append "}" ElseIf TypeName(obj) = "Collection" Then SB.Append "[" Dim Value For Each Value In obj If bFI Then bFI = False Else SB.Append "," SB.Append toString(Value) Next Value SB.Append "]" End If Case vbBoolean If obj Then SB.Append "true" Else SB.Append "false" Case vbVariant, vbArray, vbArray + vbVariant Dim sEB SB.Append multiArray(obj, 1, "", sEB) Case Else SB.Append Replace(obj, ",", ".") End Select toString = SB.toString Set SB = Nothing End Function Private Function Encode(str) As String Dim SB As New cStringBuilder Dim i As Long Dim j As Long Dim aL1 As Variant Dim aL2 As Variant Dim c As String Dim p As Boolean aL1 = Array(&H22, &H5C, &H2F, &H8, &HC, &HA, &HD, &H9) aL2 = Array(&H22, &H5C, &H2F, &H62, &H66, &H6E, &H72, &H74) For i = 1 To Len(str) p = True c = Mid(str, i, 1) For j = 0 To 7 If c = Chr(aL1(j)) Then SB.Append "\" & Chr(aL2(j)) p = False Exit For End If Next If p Then Dim a a = AscW(c) If a > 31 And a < 127 Then SB.Append c ElseIf a > -1 Or a < 65535 Then SB.Append "\u" & String(4 - Len(Hex(a)), "0") & Hex(a) End If End If Next Encode = SB.toString Set SB = Nothing End Function Private Function multiArray(aBD, iBC, sPS, ByRef sPT) ' Array BoDy, Integer BaseCount, String PoSition Dim iDU As Long Dim iDL As Long Dim i As Long On Error Resume Next iDL = LBound(aBD, iBC) iDU = UBound(aBD, iBC) Dim SB As New cStringBuilder Dim sPB1, sPB2 ' String PointBuffer1, String PointBuffer2 If Err.Number = 9 Then sPB1 = sPT & sPS For i = 1 To Len(sPB1) If i <> 1 Then sPB2 = sPB2 & "," sPB2 = sPB2 & Mid(sPB1, i, 1) Next ' multiArray = multiArray & toString(Eval("aBD(" & sPB2 & ")")) SB.Append toString(aBD(sPB2)) Else sPT = sPT & sPS SB.Append "[" For i = iDL To iDU SB.Append multiArray(aBD, iBC + 1, i, sPT) If i < iDU Then SB.Append "," Next SB.Append "]" sPT = Left(sPT, iBC - 2) End If Err.Clear multiArray = SB.toString Set SB = Nothing End Function ' Miscellaneous JSON functions Public Function StringToJSON(st As String) As String Const FIELD_SEP = "~" Const RECORD_SEP = "|" Dim sFlds As String Dim sRecs As New cStringBuilder Dim lRecCnt As Long Dim lFld As Long Dim fld As Variant Dim rows As Variant lRecCnt = 0 If st = "" Then StringToJSON = "null" Else rows = Split(st, RECORD_SEP) For lRecCnt = LBound(rows) To UBound(rows) sFlds = "" fld = Split(rows(lRecCnt), FIELD_SEP) For lFld = LBound(fld) To UBound(fld) Step 2 sFlds = (sFlds & IIf(sFlds <> "", ",", "") & """" & fld(lFld) & """:""" & toUnicode(fld(lFld + 1) & "") & """") Next 'fld sRecs.Append IIf((Trim(sRecs.toString) <> ""), "," & vbCrLf, "") & "{" & sFlds & "}" Next 'rec StringToJSON = ("( {""Records"": [" & vbCrLf & sRecs.toString & vbCrLf & "], " & """RecordCount"":""" & lRecCnt & """ } )") End If End Function Public Function RStoJSON(rs As ADODB.Recordset) As String On Error GoTo errHandler Dim sFlds As String Dim sRecs As New cStringBuilder Dim lRecCnt As Long Dim fld As ADODB.Field lRecCnt = 0 If rs.State = adStateClosed Then RStoJSON = "null" Else If rs.EOF Or rs.BOF Then RStoJSON = "null" Else Do While Not rs.EOF And Not rs.BOF lRecCnt = lRecCnt + 1 sFlds = "" For Each fld In rs.Fields sFlds = (sFlds & IIf(sFlds <> "", ",", "") & """" & fld.Name & """:""" & toUnicode(fld.Value & "") & """") Next 'fld sRecs.Append IIf((Trim(sRecs.toString) <> ""), "," & vbCrLf, "") & "{" & sFlds & "}" rs.MoveNext Loop RStoJSON = ("( {""Records"": [" & vbCrLf & sRecs.toString & vbCrLf & "], " & """RecordCount"":""" & lRecCnt & """ } )") End If End If Exit Function errHandler: End Function 'Public Function JsonRpcCall(url As String, methName As String, args(), Optional user As String, Optional pwd As String) As Object ' Dim r As Object ' Dim cli As Object ' Dim pText As String ' Static reqId As Integer ' ' reqId = reqId + 1 ' ' Set r = CreateObject("Scripting.Dictionary") ' r("jsonrpc") = "2.0" ' r("method") = methName ' r("params") = args ' r("id") = reqId ' ' pText = toString(r) ' ' Set cli = CreateObject("MSXML2.XMLHTTP.6.0") ' ' Set cli = New MSXML2.XMLHTTP60 ' If Len(user) > 0 Then ' If Not IsMissing(user) Then ' cli.Open "POST", url, False, user, pwd ' Else ' cli.Open "POST", url, False ' End If ' cli.setRequestHeader "Content-Type", "application/json" ' cli.Send pText ' ' If cli.Status <> 200 Then ' Err.Raise vbObjectError + INVALID_RPC_CALL + cli.Status, , cli.statusText ' End If ' ' Set r = parse(cli.responseText) ' Set cli = Nothing ' ' If r("id") <> reqId Then Err.Raise vbObjectError + INVALID_RPC_CALL, , "Bad Response id" ' ' If r.Exists("error") Or Not r.Exists("result") Then ' Err.Raise vbObjectError + INVALID_RPC_CALL, , "Json-Rpc Response error: " & r("error")("message") ' End If ' ' If Not r.Exists("result") Then Err.Raise vbObjectError + INVALID_RPC_CALL, , "Bad Response, missing result" ' ' Set JsonRpcCall = r("result") 'End Function Public Function toUnicode(str As String) As String Dim x As Long Dim uStr As New cStringBuilder Dim uChrCode As Integer For x = 1 To Len(str) uChrCode = Asc(Mid(str, x, 1)) Select Case uChrCode Case 8: ' backspace uStr.Append "\b" Case 9: ' tab uStr.Append "\t" Case 10: ' line feed uStr.Append "\n" Case 12: ' formfeed uStr.Append "\f" Case 13: ' carriage return uStr.Append "\r" Case 34: ' quote uStr.Append "\""" Case 39: ' apostrophe uStr.Append "\'" Case 92: ' backslash uStr.Append "\\" Case 123, 125: ' "{" and "}" uStr.Append ("\u" & Right("0000" & Hex(uChrCode), 4)) Case Is < 32, Is > 127: ' non-ascii characters uStr.Append ("\u" & Right("0000" & Hex(uChrCode), 4)) Case Else uStr.Append Chr$(uChrCode) End Select Next toUnicode = uStr.toString Exit Function End Function Private Sub Class_Initialize() psErrors = "" End Sub
Option Explicit Dim dictVars As New Dictionary Dim plNestCount As Long Public Function Eval(sJSON As String) As String Dim SB As New cStringBuilder Dim o As Object Dim c As Object Dim i As Long Set o = JSON.parse(sJSON) If (JSON.GetParserErrors = "") And Not (o Is Nothing) Then For i = 1 To o.Count Select Case VarType(o.item(i)) Case vbNull SB.Append "null" Case vbDate SB.Append CStr(o.item(i)) Case vbString SB.Append CStr(o.item(i)) Case Else Set c = o.item(i) SB.Append ExecCommand(c) End Select Next Else MsgBox JSON.GetParserErrors, vbExclamation, "Parser Error" End If Eval = SB.toString End Function Public Function ExecCommand(ByRef obj As Variant) As String Dim SB As New cStringBuilder If plNestCount > 40 Then ExecCommand = "ERROR: Nesting level exceeded." Else plNestCount = plNestCount + 1 Select Case VarType(obj) Case vbNull SB.Append "null" Case vbDate SB.Append CStr(obj) Case vbString SB.Append CStr(obj) Case vbObject Dim i As Long Dim j As Long Dim this As Object Dim key Dim paramKeys If TypeName(obj) = "Dictionary" Then Dim sOut As String Dim sRet As String Dim keys keys = obj.keys For i = 0 To obj.Count - 1 sRet = "" key = keys(i) If VarType(obj.item(key)) = vbString Then sRet = obj.item(key) Else Set this = obj.item(key) End If ' command implementation Select Case LCase(key) Case "alert": MsgBox ExecCommand(this.item("message")), vbInformation, ExecCommand(this.item("title")) Case "input": SB.Append InputBox(ExecCommand(this.item("prompt")), ExecCommand(this.item("title")), ExecCommand(this.item("default"))) Case "switch" sOut = ExecCommand(this.item("default")) sRet = LCase(ExecCommand(this.item("case"))) For j = 0 To this.item("items").Count - 1 If LCase(this.item("items").item(j + 1).item("case")) = sRet Then sOut = ExecCommand(this.item("items").item(j + 1).item("return")) Exit For End If Next SB.Append sOut Case "set": If dictVars.Exists(this.item("name")) Then dictVars.item(this.item("name")) = ExecCommand(this.item("value")) Else dictVars.Add this.item("name"), ExecCommand(this.item("value")) End If Case "get": sRet = ExecCommand(dictVars(CStr(this.item("name")))) If sRet = "" Then sRet = ExecCommand(this.item("default")) End If SB.Append sRet Case "if" Dim val1 As String Dim val2 As String Dim bRes As Boolean val1 = ExecCommand(this.item("value1")) val2 = ExecCommand(this.item("value2")) bRes = False Select Case LCase(this.item("type")) Case "eq" ' = If LCase(val1) = LCase(val2) Then bRes = True End If Case "gt" ' > If val1 > val2 Then bRes = True End If Case "lt" ' < If val1 < val2 Then bRes = True End If Case "gte" ' >= If val1 >= val2 Then bRes = True End If Case "lte" ' <= If val1 <= val2 Then bRes = True End If End Select If bRes Then SB.Append ExecCommand(this.item("true")) Else SB.Append ExecCommand(this.item("false")) End If Case "return" SB.Append obj.item(key) Case Else If TypeName(this) = "Dictionary" Then paramKeys = this.keys For j = 0 To this.Count - 1 If j > 0 Then sRet = sRet & "," End If sRet = sRet & CStr(this.item(paramKeys(j))) Next End If SB.Append "<%" & UCase(key) & "(" & sRet & ")%>" End Select Next i ElseIf TypeName(obj) = "Collection" Then Dim Value For Each Value In obj SB.Append ExecCommand(Value) Next Value End If Set this = Nothing Case vbBoolean If obj Then SB.Append "true" Else SB.Append "false" Case vbVariant, vbArray, vbArray + vbVariant Case Else SB.Append Replace(obj, ",", ".") End Select plNestCount = plNestCount - 1 End If ExecCommand = SB.toString Set SB = Nothing End Function
Dim strFunc1 As String, strFunc2 As String, strFunc3 As String
Dim objSC As Object
Dim objJS1 As Object, objJS2, objJS3
Set objSC = CreateObject("ScriptControl")
objSC.Language = "JScript"
strFunc1 = "function getjson1(s) { return eval('(' + s + ')'); }"
strFunc2 = "function getjson2(s) { return eval('(' + s + ').d[0].c[0].e[0].o.ah'); }"
strFunc3 = "function getjson3(s) { return eval('(' + s + ').d[0].c[0].e[0].o'); }"
's = "function j(s) { return eval('(' + s + ').people[1]'); }"
objSC.AddCode strFunc1
objSC.AddCode strFunc2
objSC.AddCode strFunc3
Set objJS1 = objSC.CodeObject.getjson1(strText)
Set objJS2 = objSC.CodeObject.getjson2(strText)
Set objJS3 = objSC.CodeObject.getjson3(strText)
Dim s1, s2
s1 = CallByName(objJS2, "1", VbGet)
s2 = CallByName(objJS3, "1x2", VbGet)