作者:RCDMK - rcdmk[at]hotmail[dot]com
许可证:
使用方法:
在页面顶部的页声明中设置它以应用于整个页面(例如:
<%@ LCID=1046 %>
)设置
Session
对象以便在整个会话中的所有页面中生效(例如:Session.LCID = 1046
)或者在使用类之前设置
Response
对象,以在页面的这个点之后生效(例如:Response.LCID = 1046
)
Response.LCID = 1046 ' 必须!在这里设置你的LCID(1046代表巴西)。也可以是页面声明的LCID属性或Session.LCID属性' 实例化类set JSON = New JSONobject' 添加属性JSON.Add "prop1", "someString"JSON.Add "prop2", 12.3JSON.Add "prop3", Array(1, 2, "three")' 移除属性JSON.Remove "prop2"JSON.Remove "thisDoesNotExistsAndWillDoNothing"' 更改值JSON.Change "prop1", "someOtherString"JSON.Change "prop4", "thisWillBeCreated" ' 这个属性不存在,将会自动生成' 获取值Response.Write JSON.Value("prop1") & "<br>"Response.Write JSON.Value("prop2") & "<br>"Response.Write JSON("prop3").Serialize() & "<br>" ' 默认函数相当于 `.Value(propName)` - 此属性返回一个JSON数组对象Response.Write JSON("prop4") & "<br>"' 获取格式化的JSON输出Dim jsonString jsonString = JSON.Serialize() ' 将包含JSON对象的字符串表示形式JSON.Write() ' 相当于:Response.Write JSON.Serialize()' 加载并解析JSON格式的字符串jsonString = "[{ ""strings"" : ""valorTexto"", ""numbers"": 123.456, ""arrays"": [1, ""2"", 3.4, [5, 6, [7, 8]]], ""objects"": { ""prop1"": ""outroTexto"", ""prop2"": [ { ""id"": 1, ""name"": ""item1"" }, { ""id"": 2, ""name"": ""item2"", ""teste"": { ""maisum"": [1, 2, 3] } } ] } }]" ' 因VBScript引号转义而使用双双引号set oJSONoutput = JSON.Parse(jsonString) ' 这个方法返回已解析的对象。数组会被解析成JSONarray对象JSON.Write() ' 输出:'{"data":[{"strings":"valorTexto","numbers":123.456,"arrays":[1,"2",3.4,[5,6,[7,8]]],"objects":{"prop1":"outroTexto","prop2":[{"id":1,"name":"item1"},{"id":2,"name":"item2","teste":{"maisum":[1,2,3]}}]}}]}'oJSONoutput.Write() ' 输出:'[{"strings":"valorTexto","numbers":123.456,"arrays":[1,"2",3.4,[5,6,[7,8]]],"objects":{"prop1":"outroTexto","prop2":[{"id":1,"name":"item1"},{"id":2,"name":"item2","teste":{"maisum":[1,2,3]}}]}}]'' 如果字符串表示的是一个对象(不是对象数组),则当前对象会被返回,因此不需要将结果赋给新变量jsonString = "{ ""strings"" : ""valorTexto"", ""numbers"": 123.456, ""arrays"": [1, ""2"", 3.4, [5, 6, [7, 8]]] }"JSON.Parse(jsonString) JSON.Write() ' 输出:'{"strings":"valorTexto","numbers":123.456,"arrays":[1,"2",3.4,[5,6,[7,8]]]}'
' 从ADODB.Recordset加载记录dim cn, rsset cn = CreateObject("ADODB.Connection") cn.Open "yourConnectionStringGoesHere"set rs = cn.execute("SELECT id, nome, valor FROM pedidos ORDER BY id ASC")' 也可以是:' set rs = CreateObject("ADODB.Recordset")' rs.Open "SELECT id, nome, valor FROM pedidos ORDER BY id ASC", cn JSON.LoadRecordset rs JSONarr.LoadRecordset rs rs.Close cn.Closeset rs = Nothingset cn = NothingJSON.Write() ' 输出:'{"data":[{"id":1,"nome":"nome 1","valor":10.99},{"id":2,"nome":"nome 2","valor":19.1}]}'JSONarr.Write() ' 输出:'[{"id":1,"nome":"nome 1","valor":10.99},{"id":2,"nome":"nome 2","valor":19.1}]'
JSON.defaultPropertyName = "CustomName"JSON.Write() ' 输出:'{"CustomName":[{"id":1,"nome":"nome 1","valor":10.99},{"id":2,"nome":"nome 2","valor":19.1}]}'
' 实例化类set JSONarr = New JSONarray' 向数组中添加元素JSONarr.Push JSON ' 可以为JSON对象,甚至是JSON数组JSONarr.Push 1.25 ' 可以为数字JSONarr.Push "and strings too"' 写入到页面JSONarr.Write() ' 你会猜到吗?这与JSON对象的Write方法的效果相同
dim i, item' 易读的循环for each item in JSONarr.items if isObject(item) and typeName(item) = "JSONobject" then item.write() elseif typeOf item Is JSONobject then ' For clarity, since VBA doesn't support "typeName" item.write() else Response.Write item end if Response.Write "<br>"next' 速度快但可读性较差for i = 0 to JSONarr.length - 1 if isObject(JSONarr(i)) then set item = JSONarr(i) if typeOf item Is JSONobject then ' For clarity, since VBA doesn't support "typeName" item.write() else Response.Write item end if elseif Not IsEmpty(JSONarr(i)) Then ' Avoid error when accessing array elements directly item = JSONarr(i) Response.Write item end if Response.Write "<br>"next
使用示例:
<% Option Explicit Response.LCID = 1046 ' Brazilian LCID (use your locale code here). ' Could also be the LCID property of the page declaration or Session.LCID to set it to the entire session. %> <!--#include file="jsonObject.class.asp" --> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>ASPJSON</title> <style type="text/css"> body { font-family: Arial, Helvetica, sans-serif; } pre { border: solid 1px #CCCCCC; background-color: #EEE; padding: 5px; text-indent: 0; width: 90%; white-space: pre-wrap; word-wrap: break-word; } </style> </head> <body> <h1>JSON Object and Array Tests</h1> <% server.ScriptTimeout = 10 dim jsonObj, jsonString, jsonArr, outputObj dim testLoad, testAdd, testRemove, testValue, testChange, testArrayPush, testLoadRecordset dim testLoadArray, testChangeDefaultPropertyName, testGetItemAt testLoad = true testLoadArray = true testAdd = true testRemove = true testValue = true testChange = true testArrayPush = true testLoadRecordset = true testChangeDefaultPropertyName = true set jsonObj = new JSONobject set jsonArr = new jsonArray jsonObj.debug = false if testLoad then jsonString = "{ ""strings"" : ""valorTexto"", ""numbers"": 123.456, ""bools"": true, ""arrays"": [1, ""2"", 3.4, [5, -6, [7, 8, [[[""9"", ""10""]]]]]], ""emptyArray"": [], ""emptyObject"": {}, ""objects"": { ""prop1"": ""outroTexto"", ""prop2"": [ { ""id"": 1, ""name"": ""item1"" }, { ""id"": 2, ""name"": ""item2"", ""teste"": { ""maisum"": [1, 2, 3] } } ] }, ""multiline"": ""Texto com\r\nMais de\r\numa linha e escapado com \\."" }" if testLoadArray then jsonString = "[" & jsonString & "]" set outputObj = jsonObj.parse(jsonString) %> <h3>Parse Input</h3> <pre><%= jsonString %></pre> <% end if if testAdd then dim arr, multArr, nestedObject arr = Array(1, "teste", 234.56, "mais teste", "234", now) redim multArr(2, 3) multArr(0, 0) = "0,0" multArr(0, 1) = "0,1" multArr(0, 2) = "0,2" multArr(0, 3) = "0,3" multArr(1, 0) = "1,0" multArr(1, 1) = "1,1" multArr(1, 2) = "1,2" multArr(1, 3) = "1,3" multArr(2, 0) = "2,0" multArr(2, 1) = "2,1" multArr(2, 2) = "2,2" multArr(2, 3) = "2,3" jsonObj.add "nome", "Jozé" jsonObj.add "ficticio", true jsonObj.add "idade", 25 jsonObj.add "saldo", -52 jsonObj.add "bio", "Nascido em São Paulo\Brasil" & vbcrlf & "Sem filhos" & vbcrlf & vbtab & "Jogador de WoW" jsonObj.add "data", now jsonObj.add "lista", arr jsonObj.add "lista2", multArr set nestedObject = new JSONobject nestedObject.add "sub1", "value of sub1" nestedObject.add "sub2", "value of ""sub2""" jsonObj.add "nested", nestedObject end if if testRemove then jsonObj.remove "numbers" jsonObj.remove "aNonExistantPropertyName" ' this sould run silently, even to non existant properties end if if testValue then %><h3>Get Values</h3><% response.write "nome: " & jsonObj.value("nome") & "<br>" response.write "idade: " & jsonObj("idade") & "<br>" ' short syntax response.write "non existant property:" & jsonObj("aNonExistantPropertyName") & "(" & typeName(jsonObj("aNonExistantPropertyName")) & ")<br>" end if if testChange then %><h3>Change Values</h3><% response.write "nome before: " & jsonObj.value("nome") & "<br>" jsonObj.change "nome", "Mario" response.write "nome after: " & jsonObj.value("nome") & "<br>" jsonObj.change "nonExisting", -1 response.write "Non existing property is created with: " & jsonObj.value("nonExisting") & "<br>" end if if testArrayPush then jsonArr.Push jsonObj jsonArr.Push 1 jsonArr.Push "strings too" end if if testLoadRecordset then %><h3>Load a Recordset</h3> <!-- METADATA TYPE="TypeLib" NAME="Microsoft ActiveX Data Objects 2.5 Library" UUID="{00000205-0000-0010-8000-00AA006D2EA4}" VERSION="2.5" --> <% dim rs set rs = createObject("ADODB.Recordset") ' prepera an in memory recordset ' could be, and mostly, loaded from a database rs.CursorType = adOpenKeyset rs.CursorLocation = adUseClient rs.LockType = adLockOptimistic rs.Fields.Append "ID", adInteger, , adFldKeyColumn rs.Fields.Append "Nome", adVarChar, 50, adFldMayBeNull rs.Fields.Append "Valor", adDecimal, 14, adFldMayBeNull rs.Fields("Valor").NumericScale = 2 rs.Open rs.AddNew rs("ID") = 1 rs("Nome") = "Nome 1" rs("Valor") = 10.99 rs.Update rs.AddNew rs("ID") = 2 rs("Nome") = "Nome 2" rs("Valor") = 29.90 rs.Update rs.moveFirst jsonObj.LoadFirstRecord rs ' or rs.moveFirst jsonArr.LoadRecordSet rs rs.Close set rs = nothing end if if testLoad then %> <h3>Parse Output</h3> <pre><%= outputObj.write %></pre> <% end if if testChangeDefaultPropertyName then jsonObj.defaultPropertyName = "CustomName" jsonArr.defaultPropertyName = "CustomArrName" end if %> <h3>JSON Object Output<% if testLoad then %> (Same as parse output: <% if typeName(jsonObj) = typeName(outputObj) then %>yes<% else %>no<% end if %>)<% end if %></h3> <pre><%= jsonObj.write %></pre> <h3>Array Output</h3> <pre><%= jsonArr.write %></pre> <h3>Array Loop</h3> <pre><% dim i, items, item ' more readable loop i = 0 response.write "For Each Loop (readability):<br>==============<br>" for each item in jsonArr.items response.write "Index " response.write i response.write ": " if isObject(item) and typeName(item) = "JSONobject" then item.write() else response.write item end if response.write "<br>" i = i + 1 next response.write "<br><br>For Loop (speed):<br>=========<br>" ' faster but less readable for i = 0 to jsonArr.length - 1 response.write "Index " response.write i response.write ": " if isObject(jsonArr(i)) then set item = jsonArr(i) if typeName(item) = "JSONobject" then item.write() else response.write item end if else item = jsonArr(i) response.write item end if response.write "<br>" next set outputObj = nothing set jsonObj = nothing set jsonArr = nothing %></pre> <h3>JSON Script Output</h3> <% dim realOutput dim expectedOutput dim javascriptCode dim javascriptkey dim jsonScr javascriptCode = "function() { alert('test'); }" javascriptKey = "script" expectedOutput = "{""" & javascriptKey & """:" & javascriptCode & "}" set jsonScr = new JSONscript jsonScr.value = javascriptCode set jsonObj = new JSONobject jsonObj.Add javascriptKey, jsonScr realOutput = jsonObj.Serialize() %><h4>Output<% if (realOutput = expectedOutput) then %> (correct)<% else %> (INCORRECT!)<% end if %></h4> <pre><%= realOutput %></pre> </body> </html>
类库文件jsonObject.class.asp:
<% ' JSON object class 3.8.1 May, 29th - 2016 ' https://github.com/rcdmk/aspJSON ' ' License MIT - see LICENCE.txt for details const JSON_ROOT_KEY = "[[JSONroot]]" const JSON_DEFAULT_PROPERTY_NAME = "data" const JSON_SPECIAL_VALUES_REGEX = "^(?:(?:t(?:r(?:ue?)?)?)|(?:f(?:a(?:l(?:se?)?)?)?)|(?:n(?:u(?:ll?)?))|(?:u(?:n(?:d(?:e(?:f(?:i(?:n(?:ed?)?)?)?)?)?)?)?))$" const JSON_ERROR_PARSE = 1 const JSON_ERROR_PROPERTY_ALREADY_EXISTS = 2 const JSON_ERROR_PROPERTY_DOES_NOT_EXISTS = 3 ' DEPRECATED const JSON_ERROR_NOT_AN_ARRAY = 4 const JSON_ERROR_NOT_A_STRING = 5 const JSON_ERROR_INDEX_OUT_OF_BOUNDS = 9 ' Numbered to have the same error number as the default "Subscript out of range" exeption class JSONobject dim i_debug, i_depth, i_parent dim i_properties, i_version, i_defaultPropertyName private vbback ' Set to true to show the internals of the parsing mecanism public property get debug debug = i_debug end property public property let debug(value) i_debug = value end property ' Gets/sets the default property name generated when loading recordsets and arrays (default "data") public property get defaultPropertyName defaultPropertyName = i_defaultPropertyName end property public property let defaultPropertyName(value) i_defaultPropertyName = value end property ' The depth of the object in the chain, starting with 1 public property get depth depth = i_depth end property ' The property pairs ("name": "value" - pairs) public property get pairs pairs = i_properties end property ' The parent object public property get parent set parent = i_parent end property public property set parent(value) set i_parent = value i_depth = i_parent.depth + 1 end property ' Constructor and destructor private sub class_initialize() i_version = "3.8.1" i_depth = 0 i_debug = false i_defaultPropertyName = JSON_DEFAULT_PROPERTY_NAME set i_parent = nothing redim i_properties(-1) vbback = Chr(8) end sub private sub class_terminate() dim i for i = 0 to ubound(i_properties) set i_properties(i) = nothing next redim i_properties(-1) end sub ' Parse a JSON string and populate the object public function parse(byval strJson) dim regex, i, size, char, prevchar, quoted dim mode, item, key, value, openArray, openObject dim actualLCID, tmpArray, tmpObj, addedToArray dim root, currentObject, currentArray log("Load string: """ & strJson & """") ' Store the actual LCID and use the en-US to conform with the JSON standard actualLCID = Response.LCID Response.LCID = 1033 strJson = trim(strJson) size = len(strJson) ' At least 2 chars to continue if size < 2 then err.raise JSON_ERROR_PARSE, TypeName(me), "Invalid JSON string to parse" ' Init the regex to be used in the loop set regex = new regexp regex.global = true regex.ignoreCase = true regex.pattern = "\w" ' setup initial values i = 0 set root = me key = JSON_ROOT_KEY mode = "init" quoted = false set currentObject = root ' main state machine do while i < size i = i + 1 char = mid(strJson, i, 1) ' root, object or array start if mode = "init" then log("Enter init") ' if we are in root, clear previous object properties if key = JSON_ROOT_KEY and TypeName(currentArray) <> "JSONarray" then redim i_properties(-1) ' Init object if char = "{" then log("Create object<ul>") if key <> JSON_ROOT_KEY or TypeName(root) = "JSONarray" then ' creates a new object set item = new JSONobject set item.parent = currentObject addedToArray = false ' Object is inside an array if TypeName(currentArray) = "JSONarray" then if currentArray.depth > currentObject.depth then ' Add it to the array set item.parent = currentArray currentArray.Push item addedToArray = true log("Added to the array") end if end if if not addedToArray then currentObject.add key, item log("Added to parent object: """ & key & """") end if set currentObject = item end if openObject = openObject + 1 mode = "openKey" ' Init Array elseif char = "[" then log("Create array<ul>") set item = new JSONarray addedToArray = false ' Array is inside an array if isobject(currentArray) and openArray > 0 then if currentArray.depth > currentObject.depth then ' Add it to the array set item.parent = currentArray currentArray.Push item addedToArray = true log("Added to parent array") end if end if if not addedToArray then set item.parent = currentObject currentObject.add key, item log("Added to parent object") end if if key = JSON_ROOT_KEY and item.depth = 1 then set root = item log("Set as root") end if set currentArray = item openArray = openArray + 1 mode = "openValue" end if ' Init a key elseif mode = "openKey" then key = "" if char = """" then log("Open key") mode = "closeKey" elseif char = "}" then ' empty objects log("Empty object") mode = "next" i = i - 1 ' we backup one char to make the next iteration get the closing bracket end if ' Fill in the key until finding a double quote " elseif mode = "closeKey" then ' If it finds a non scaped quotation, change to value mode if char = """" and prevchar <> "\" then log("Close key: """ & key & """") mode = "preValue" else key = key & char end if ' Wait until a colon char (:) to begin the value elseif mode = "preValue" then if char = ":" then mode = "openValue" log("Open value for """ & key & """") end if ' Begining of value elseif mode = "openValue" then value = "" ' If the next char is a closing square barcket (]), its closing an empty array if char = "]" then log("Closing empty array") quoted = false mode = "next" i = i - 1 ' we backup one char to make the next iteration get the closing bracket ' If it begins with a double quote, its a string value elseif char = """" then log("Open string value") quoted = true mode = "closeValue" ' If it begins with open square bracket ([), its an array elseif char = "[" then log("Open array value") quoted = false mode = "init" i = i - 1 ' we backup one char to init with '[' ' If it begins with open a bracket ({), its an object elseif char = "{" then log("Open object value") quoted = false mode = "init" i = i - 1 ' we backup one char to init with '{' else ' If its a number, start a numeric value if regex.pattern <> "\d" then regex.pattern = "\d" if regex.test(char) then log("Open numeric value") quoted = false value = char mode = "closeValue" if prevchar = "-" then value = prevchar & char end if ' special values: null, true, false and undefined elseif char = "n" or char = "t" or char = "f" or char = "u" then log("Open special value") quoted = false value = char mode = "closeValue" end if end if ' Fill in the value until finish elseif mode = "closeValue" then if quoted then if char = """" and prevchar <> "\" then log("Close string value: """ & value & """") mode = "addValue" ' special and escaped chars elseif prevchar = "\" then select case char case "n" value = value & vblf case "r" value = value & vbcr case "t" value = value & vbtab case "b" value = value & vbback ' escaped chars fix by @IT-Portal case "\" 'for \\t we must have \t (not \tab) 'here we're resetting prevchar for next iteration value = value & char char = "" ' escaped unicode syntax by @IT-Portal case "u" '\uxxxx support if IsNumeric("&H" & mid(strJson, i + 1, 4)) then value = value & ChrW("&H" & mid(strJson, i + 1, 4)) i = i + 4 else value = value & char end if case else value = value & char end select elseif char <> "\" then value = value & char end if else ' possible boolean and null values if regex.pattern <> JSON_SPECIAL_VALUES_REGEX then regex.pattern = JSON_SPECIAL_VALUES_REGEX if regex.test(char) or regex.test(value) then value = value & char if value = "true" or value = "false" or value = "null" or value = "undefined" then mode = "addValue" else char = lcase(char) ' If is a numeric char if regex.pattern <> "\d" then regex.pattern = "\d" if regex.test(char) then value = value & char ' If it's not a numeric char, but the prev char was a number ' used to catch separators and special numeric chars elseif regex.test(prevchar) or prevchar = "e" then if char = "." or char = "e" or (prevchar = "e" and (char = "-" or char = "+")) then value = value & char else log("Close numeric value: " & value) mode = "addValue" i = i - 1 end if else log("Close numeric value: " & value) mode = "addValue" i = i - 1 end if end if end if ' Add the value to the object or array elseif mode = "addValue" then if key <> "" then dim useArray useArray = false if not quoted then if isNumeric(value) then log("Value converted to number") value = cdbl(value) else log("Value converted to " & value) value = eval(value) end if end if quoted = false ' If it's inside an array if openArray > 0 and isObject(currentArray) then useArray = true ' If it's a property of an object that is inside the array ' we add it to the object instead if isObject(currentObject) then if currentObject.depth >= currentArray.depth + 1 then useArray = false end if ' else, we add it to the array if useArray then tmpArray = currentArray.items ArrayPush tmpArray, value currentArray.items = tmpArray log("Value added to array: """ & key & """: " & value) end if end if if not useArray then currentObject.add key, value log("Value added: """ & key & """") end if end if mode = "next" i = i - 1 ' Change the current mode according to the current state elseif mode = "next" then if char = "," then ' If it's an array if openArray > 0 and isObject(currentArray) then ' and the current object is a parent or sibling object if currentArray.depth >= currentObject.depth then ' start an array value log("New value") mode = "openValue" else ' start an object key log("New key") mode = "openKey" end if else ' start an object key log("New key") mode = "openKey" end if elseif char = "]" then log("Close array</ul>") ' If it's and open array, we close it and set the current array as its parent if isobject(currentArray.parent) then if TypeName(currentArray.parent) = "JSONarray" then set currentArray = currentArray.parent ' if the parent is an object elseif TypeName(currentArray.parent) = "JSONobject" then set tmpObj = currentArray.parent ' we search for the next parent array to set the current array while isObject(tmpObj) and TypeName(tmpObj) = "JSONobject" if isObject(tmpObj.parent) then set tmpObj = tmpObj.parent else tmpObj = tmpObj.parent end if wend set currentArray = tmpObj end if else currentArray = currentArray.parent end if openArray = openArray - 1 mode = "next" elseif char = "}" then log("Close object</ul>") ' If it's an open object, we close it and set the current object as it's parent if isobject(currentObject.parent) then if TypeName(currentObject.parent) = "JSONobject" then set currentObject = currentObject.parent ' If the parent is and array elseif TypeName(currentObject.parent) = "JSONarray" then set tmpObj = currentObject.parent ' we search for the next parent object to set the current object while isObject(tmpObj) and TypeName(tmpObj) = "JSONarray" set tmpObj = tmpObj.parent wend set currentObject = tmpObj end if else currentObject = currentObject.parent end if openObject = openObject - 1 mode = "next" end if end if prevchar = char loop set regex = nothing Response.LCID = actualLCID set parse = root end function ' Add a new property (key-value pair) public sub add(byval prop, byval obj) dim p getProperty prop, p if GetTypeName(p) = "JSONpair" then err.raise JSON_ERROR_PROPERTY_ALREADY_EXISTS, TypeName(me), "A property already exists with the name: " & prop & "." else dim item set item = new JSONpair item.name = prop set item.parent = me dim itemType itemType = GetTypeName(obj) if isArray(obj) then dim item2 set item2 = new JSONarray item2.items = obj set item2.parent = me set item.value = item2 elseif itemType = "Field" then item.value = obj.value elseif isObject(obj) and itemType <> "IStringList" then set item.value = obj else item.value = obj end if ArrayPush i_properties, item end if end sub ' Remove a property from the object (key-value pair) public sub remove(byval prop) dim p, i i = getProperty(prop, p) ' property exists if i > -1 then ArraySlice i_properties, i end sub ' Return the value of a property by its key public default function value(byval prop) dim p getProperty prop, p if GetTypeName(p) = "JSONpair" then if isObject(p.value) then set value = p.value else value = p.value end if else value = null end if end function ' Change the value of a property ' Creates the property if it didn't exists public sub change(byval prop, byval obj) dim p getProperty prop, p if GetTypeName(p) = "JSONpair" then if isArray(obj) then set item = new JSONarray item.items = obj set item.parent = me p.value = item elseif isObject(obj) then set p.value = obj else p.value = obj end if else add prop, obj end if end sub ' Returns the index of a property if it exists, else -1 ' @param prop as string - the property name ' @param out outProp as variant - will be filled with the property value, nothing if not found private function getProperty(byval prop, byref outProp) dim i, p, found set outProp = nothing found = false i = 0 do while i <= ubound(i_properties) set p = i_properties(i) if p.name = prop then set outProp = p found = true exit do end if i = i + 1 loop if not found then i = -1 getProperty = i end function ' Serialize the current object to a JSON formatted string public function Serialize() dim actualLCID, out actualLCID = Response.LCID Response.LCID = 1033 out = serializeObject(me) Response.LCID = actualLCID Serialize = out end function ' Writes the JSON serialized object to the response public sub write() response.write Serialize end sub ' Helpers ' Serializes a JSON object to JSON formatted string public function serializeObject(obj) dim out, prop, value, i, pairs, valueType out = "{" pairs = obj.pairs for i = 0 to ubound(pairs) set prop = pairs(i) if out <> "{" then out = out & "," if isobject(prop.value) then set value = prop.value else value = prop.value end if if prop.name = JSON_ROOT_KEY then out = out & """" & obj.defaultPropertyName & """:" else out = out & """" & prop.name & """:" end if if isArray(value) or GetTypeName(value) = "JSONarray" then out = out & serializeArray(value) elseif isObject(value) and GetTypeName(value) = "JSONscript" then out = out & value.Serialize() elseif isObject(value) then out = out & serializeObject(value) else out = out & serializeValue(value) end if next out = out & "}" serializeObject = out end function ' Serializes a value to a valid JSON formatted string representing the value ' (quoted for strings, the type name for objects, null for nothing and null values) public function serializeValue(byval value) dim out select case lcase(GetTypeName(value)) case "null" out = "null" case "nothing" out = "undefined" case "boolean" if value then out = "true" else out = "false" end if case "byte", "integer", "long", "single", "double", "currency", "decimal" out = value case "date" out = """" & year(value) & "-" & padZero(month(value), 2) & "-" & padZero(day(value), 2) & "T" & padZero(hour(value), 2) & ":" & padZero(minute(value), 2) & ":" & padZero(second(value), 2) & """" case "string", "char", "empty" out = """" & EscapeCharacters(value) & """" case else out = """" & GetTypeName(value) & """" end select serializeValue = out end function ' Pads a numeric string with zeros at left private function padZero(byval number, byval length) dim result result = number while len(result) < length result = "0" & result wend padZero = result end function ' Serializes an array item to JSON formatted string private function serializeArrayItem(byref elm) dim out, val if isobject(elm) then if GetTypeName(elm) = "JSONobject" then set val = elm elseif GetTypeName(elm) = "JSONarray" then val = elm.items elseif isObject(elm.value) then set val = elm.value else val = elm.value end if else val = elm end if if isArray(val) or GetTypeName(val) = "JSONarray" then out = out & serializeArray(val) elseif isObject(val) then out = out & serializeObject(val) else out = out & serializeValue(val) end if serializeArrayItem = out end function ' Serializes an array or JSONarray object to JSON formatted string public function serializeArray(byref arr) dim i, j, k, dimensions, out, innerArray, elm, val out = "[" if isobject(arr) then log("Serializing jsonArray object") innerArray = arr.items else log("Serializing VB array") innerArray = arr end if dimensions = NumDimensions(innerArray) if dimensions > 1 then log("Multidimensional array") for j = 0 to ubound(innerArray, 1) out = out & "[" for k = 0 to ubound(innerArray, 2) if k > 0 then out = out & "," if isObject(innerArray(j, k)) then set elm = innerArray(j, k) else elm = innerArray(j, k) end if out = out & serializeArrayItem(elm) next out = out & "]" next else for j = 0 to ubound(innerArray) if j > 0 then out = out & "," if isobject(innerArray(j)) then set elm = innerArray(j) else elm = innerArray(j) end if out = out & serializeArrayItem(elm) next end if out = out & "]" serializeArray = out end function ' Returns the number of dimensions an array has public Function NumDimensions(byref arr) Dim dimensions dimensions = 0 On Error Resume Next Do While Err.number = 0 dimensions = dimensions + 1 UBound arr, dimensions Loop On Error Goto 0 NumDimensions = dimensions - 1 End Function ' Pushes (adds) a value to an array, expanding it public function ArrayPush(byref arr, byref value) redim preserve arr(ubound(arr) + 1) if isobject(value) then set arr(ubound(arr)) = value else arr(ubound(arr)) = value end if ArrayPush = arr end function ' Removes a value from an array private function ArraySlice(byref arr, byref index) dim i, upperBound i = index upperBound = ubound(arr) do while i < upperBound if isObject(arr(i)) then set arr(i) = arr(i + 1) else arr(i) = arr(i + 1) end if i = i + 1 loop redim preserve arr(upperBound - 1) ArraySlice = arr end function ' Load properties from an ADO RecordSet object into an array ' @param rs as ADODB.RecordSet public sub LoadRecordSet(byref rs) dim arr, obj, field set arr = new JSONArray while not rs.eof set obj = new JSONobject for each field in rs.fields obj.Add field.name, field.value next arr.Push obj rs.movenext wend set obj = nothing add JSON_ROOT_KEY, arr end sub ' Load properties from the first record of an ADO RecordSet object ' @param rs as ADODB.RecordSet public sub LoadFirstRecord(byref rs) dim field for each field in rs.fields add field.name, field.value next end sub ' Returns the value's type name (usefull for types not supported by VBS) public function GetTypeName(byval value) dim valueType on error resume next valueType = TypeName(value) if err.number <> 0 then if varType(value) = 14 then valueType = "Decimal" end if on error goto 0 GetTypeName = valueType end function ' Escapes special characters in the text ' @param text as String public function EscapeCharacters(byval text) dim result result = text if not isNull(text) then result = cstr(result) result = replace(result, "\", "\\") result = replace(result, """", "\""") result = replace(result, vbcr, "\r") result = replace(result, vblf, "\n") result = replace(result, vbtab, "\t") result = replace(result, vbback, "\b") end if EscapeCharacters = result end function ' Used to write the log messages to the response on debug mode private sub log(byval msg) if i_debug then response.write "<li>" & msg & "</li>" & vbcrlf end sub end class ' JSON array class ' Represents an array of JSON objects and values class JSONarray dim i_items, i_depth, i_parent, i_version, i_defaultPropertyName ' The class version public property get version version = i_version end property ' The actual array items public property get items items = i_items end property public property let items(value) if isArray(value) then i_items = value else err.raise JSON_ERROR_NOT_AN_ARRAY, TypeName(me), "The value assigned is not an array." end if end property ' The length of the array public property get length length = ubound(i_items) + 1 end property ' The depth of the array in the chain (starting with 1) public property get depth depth = i_depth end property ' The parent object or array public property get parent set parent = i_parent end property public property set parent(value) set i_parent = value i_depth = i_parent.depth + 1 i_defaultPropertyName = i_parent.defaultPropertyName end property ' Gets/sets the default property name generated when loading recordsets and arrays (default "data") public property get defaultPropertyName defaultPropertyName = i_defaultPropertyName end property public property let defaultPropertyName(value) i_defaultPropertyName = value end property ' Constructor and destructor private sub class_initialize i_version = "2.3.5" i_defaultPropertyName = JSON_DEFAULT_PROPERTY_NAME redim i_items(-1) i_depth = 0 end sub private sub class_terminate dim i, j, js, dimensions dimensions = 0 On Error Resume Next Do While Err.number = 0 dimensions = dimensions + 1 UBound i_items, dimensions Loop On Error Goto 0 dimensions = dimensions - 1 for i = 1 to dimensions for j = 0 to ubound(i_items, i) if dimensions = 1 then set i_items(j) = nothing else set i_items(i - 1, j) = nothing end if next next end sub ' Adds a value to the array public sub Push(byref value) dim js, instantiated if typeName(i_parent) = "JSONobject" then set js = i_parent i_defaultPropertyName = i_parent.defaultPropertyName else set js = new JSONobject js.defaultPropertyName = i_defaultPropertyName instantiated = true end if js.ArrayPush i_items, value if instantiated then set js = nothing end sub ' Load properties from a ADO RecordSet object public sub LoadRecordSet(byref rs) dim obj, field while not rs.eof set obj = new JSONobject for each field in rs.fields obj.Add field.name, field.value next Push obj rs.movenext wend set obj = nothing end sub ' Returns the item at the specified index ' @param index as int - the desired item index public default function ItemAt(byval index) dim len len = me.length if len > 0 and index < len then if isObject(i_items(index)) then set ItemAt = i_items(index) else ItemAt = i_items(index) end if else err.raise JSON_ERROR_INDEX_OUT_OF_BOUNDS, TypeName(me), "Index out of bounds." end if end function ' Serializes this JSONarray object in JSON formatted string value ' (uses the JSONobject.SerializeArray method) public function Serialize() dim js, out, instantiated, actualLCID actualLCID = Response.LCID Response.LCID = 1033 if not isEmpty(i_parent) then if TypeName(i_parent) = "JSONobject" then set js = i_parent i_defaultPropertyName = i_parent.defaultPropertyName end if end if if isEmpty(js) then set js = new JSONobject js.defaultPropertyName = i_defaultPropertyName instantiated = true end if out = js.SerializeArray(me) if instantiated then set js = nothing Response.LCID = actualLCID Serialize = out end function ' Writes the serialized array to the response public function Write() Response.Write Serialize() end function end class class JSONscript dim i_version dim s_value, s_nullString ' The value public property get value value = s_value end property public property let value(newValue) if (TypeName(newValue) <> "String") then err.raise JSON_ERROR_NOT_A_STRING, TypeName(me), "The value assigned is not a string." end if if (len(newValue) = 0) then newValue = s_nullString s_value = newValue end property ' Constructor and destructor private sub class_initialize() i_version = "1.0.0" s_nullString = "null" s_value = s_nullString end sub ' Serializes this object by outputting the raw value public function Serialize() Serialize = s_value end function ' Writes the serialized object to the response public function Write() Response.Write Serialize() end function end class ' JSON pair class ' represents a name/value pair of a JSON object class JSONpair dim i_name, i_value dim i_parent ' The name or key of the pair public property get name name = i_name end property public property let name(val) i_name = val end property ' The value of the pair public property get value if isObject(i_value) then set value = i_value else value = i_value end if end property public property let value(val) i_value = val end property public property set value(val) set i_value = val end property ' The parent object public property get parent set parent = i_parent end property public property set parent(val) set i_parent = val end property ' Constructor and destructor private sub class_initialize end sub private sub class_terminate if isObject(value) then set value = nothing end sub end class %>
来源:https://gitcode.com/gh_mirrors/as/aspJSON/blob/master/jsonObject.class.asp