222 lines
7.0 KiB
VB.net
222 lines
7.0 KiB
VB.net
Imports System.Text.RegularExpressions
|
|
|
|
Public Class JSONObject
|
|
|
|
#Region "Shared Variables"
|
|
Private Shared ReadOnly reProp As New Regex("(?<=(^|\,)\s*)([^\:]+)\s*\:\s*([^\,]+)", RegexOptions.Compiled)
|
|
Private Shared ReadOnly reReplaced As New Regex("^\$\[\d+\]$", RegexOptions.Compiled)
|
|
#End Region
|
|
|
|
#Region "Shared Functions"
|
|
|
|
Private Shared Function TokenizeJSON(ByVal json As String, ByVal l As List(Of String)) As String
|
|
Dim r As String = String.Empty
|
|
Dim nestable As String = "()[]{}"
|
|
Dim stringable As String = """'"
|
|
Dim nested As New Stack(Of Char)
|
|
Dim stringing As Char? = Nothing
|
|
Dim start As Integer = -1
|
|
l.Clear()
|
|
|
|
For i As Integer = 0 To json.Length - 1
|
|
Dim c As Char = json(i)
|
|
If stringing IsNot Nothing Then
|
|
If stringing = c Then
|
|
stringing = Nothing
|
|
If nested.Count = 0 Then
|
|
r &= "$[" & l.Count.ToString() & "]"
|
|
l.Add(json.Substring(start, i - start + 1))
|
|
End If
|
|
End If
|
|
ElseIf stringable.IndexOf(c) > -1 Then
|
|
stringing = c
|
|
If nested.Count = 0 Then start = i
|
|
ElseIf nestable.IndexOf(c) Mod 2 = 0 Then
|
|
If nested.Count = 0 Then start = i
|
|
nested.Push(c)
|
|
ElseIf nested.Count > 0 Then
|
|
If nestable.IndexOf(nested.Peek()) + 1 = nestable.IndexOf(c) Then
|
|
nested.Pop()
|
|
If nested.Count = 0 Then
|
|
r &= "$[" & l.Count.ToString() & "]"
|
|
l.Add(json.Substring(start, i - start + 1))
|
|
End If
|
|
End If
|
|
Else
|
|
r &= If(c = "\" OrElse c = "$", "\" & c, c)
|
|
End If
|
|
Next
|
|
|
|
Return r
|
|
End Function
|
|
|
|
Private Shared Function ParseJSONObject(ByVal json As String) As Dictionary(Of String, String)
|
|
Dim r As New Dictionary(Of String, String)
|
|
Dim l As New List(Of String)
|
|
|
|
'Trim any leading or trailing object delimiters found in JSON objects.
|
|
json = json.TrimStart(" "c).TrimEnd(" "c)
|
|
json = json.Substring(1).Substring(0, json.Length - 2)
|
|
|
|
'Tokenize the JSON object.
|
|
json = TokenizeJSON(json, l)
|
|
|
|
'Parse the JSON object.
|
|
For Each m As Match In reProp.Matches(json)
|
|
Dim name As String = m.Groups(2).Value.TrimStart()
|
|
Dim value As String = m.Groups(3).Value
|
|
If reReplaced.IsMatch(name) Then name = l(Integer.Parse(name.Substring(2, name.Length - 3)))
|
|
If reReplaced.IsMatch(value) Then value = l(Integer.Parse(value.Substring(2, value.Length - 3)))
|
|
name = name.Trim("'"c, """"c)
|
|
r.Add(name, value)
|
|
Next
|
|
|
|
'Return the result.
|
|
Return r
|
|
End Function
|
|
|
|
Private Shared Function ParseJSONArray(ByVal json As String) As String()
|
|
Dim l As New List(Of String)
|
|
Dim r As New List(Of String)
|
|
|
|
'Trim any leading or trailing array delimiters found in JSON objects, but only one on each side.
|
|
json = json.Trim()
|
|
json = json.Substring(1, json.Length - 2)
|
|
|
|
'Tokenize the JSON array.
|
|
json = TokenizeJSON(json, l)
|
|
|
|
'Parse and return the JSON array.
|
|
For Each x As String In json.Split(",")
|
|
x = x.Trim()
|
|
If reReplaced.IsMatch(x) Then
|
|
r.Add(l(Integer.Parse(x.Substring(2, x.Length - 3))))
|
|
Else
|
|
r.Add(x)
|
|
End If
|
|
Next
|
|
Return r.ToArray()
|
|
End Function
|
|
|
|
#End Region
|
|
|
|
#Region "Variables"
|
|
Private ReadOnly _properties As Dictionary(Of String, String)
|
|
Private ReadOnly list As New List(Of JSONObject)
|
|
#End Region
|
|
|
|
#Region "Constructor"
|
|
Public Sub New(ByVal json As String)
|
|
If json.Substring(0, 1) = "{" Then
|
|
_properties = JSONObject.ParseJSONObject(json)
|
|
ElseIf json.Substring(0, 1) = "[" Then
|
|
For Each x As String In JSONObject.ParseJSONArray(json)
|
|
Dim obj As JSONObject = New JSONObject(x)
|
|
list.Add(obj)
|
|
Next
|
|
End If
|
|
End Sub
|
|
#End Region
|
|
|
|
#Region "Methods"
|
|
|
|
Public Sub Destroy()
|
|
_properties.Clear()
|
|
list.Clear()
|
|
GC.Collect()
|
|
End Sub
|
|
|
|
Public Function GetJsonArray() As List(Of JSONObject)
|
|
Return list
|
|
End Function
|
|
|
|
Public Function GetArray(ByVal name As String) As List(Of JSONObject)
|
|
If _properties.ContainsKey(name) Then
|
|
list.Clear()
|
|
Dim prop As String = _properties(name)
|
|
For Each x As String In JSONObject.ParseJSONArray(prop)
|
|
Dim obj As JSONObject = New JSONObject(x)
|
|
list.Add(obj)
|
|
Next
|
|
End If
|
|
Return list
|
|
End Function
|
|
|
|
Public Function GetProperty(ByVal name As String) As JSONValue
|
|
If _properties.ContainsKey(name) Then Return Evaluate(_properties(name))
|
|
|
|
Return New JSONValue(JSONType.undefined, Nothing)
|
|
End Function
|
|
|
|
Private Function Evaluate(ByVal json As String) As JSONValue
|
|
Dim intValue As Integer
|
|
Dim floatValue As Double
|
|
json = json.TrimStart("("c).TrimEnd(")"c)
|
|
|
|
If json <> String.Empty Then
|
|
If json(0) = "{"c Then
|
|
Return New JSONValue(JSONType.object, New JSONObject(json))
|
|
ElseIf json(0) = "["c Then
|
|
For Each x As String In JSONObject.ParseJSONArray(json)
|
|
list.Add(New JSONObject(x))
|
|
Next
|
|
ElseIf json(0) = "'"c OrElse json(0) = """"c Then
|
|
Return New JSONValue(JSONType.string, json.Substring(1, json.Length - 2))
|
|
ElseIf Integer.Parse(json) Then
|
|
intValue = Integer.Parse(json)
|
|
Return New JSONValue(JSONType.int, intValue)
|
|
ElseIf Double.Parse(json) Then
|
|
floatValue = Double.Parse(json)
|
|
Return New JSONValue(JSONType.double, floatValue)
|
|
ElseIf json = "true" Then
|
|
Return New JSONValue(JSONType.bool, True)
|
|
ElseIf json = "false" Then
|
|
Return New JSONValue(JSONType.bool, False)
|
|
ElseIf json = "null" Then
|
|
Return New JSONValue(JSONType.null, Nothing)
|
|
End If
|
|
End If
|
|
|
|
Return New JSONValue(JSONType.undefined, Nothing)
|
|
End Function
|
|
#End Region
|
|
|
|
End Class
|
|
|
|
Public Class JSONValue
|
|
Private _type As JSONType
|
|
Private _value As Object
|
|
|
|
Public Sub New(ByVal type As JSONType, ByVal value As Object)
|
|
_type = type
|
|
_value = value
|
|
End Sub
|
|
|
|
Public ReadOnly Property Type() As JSONType
|
|
Get
|
|
Return _type
|
|
End Get
|
|
End Property
|
|
|
|
Public ReadOnly Property Value() As Object
|
|
Get
|
|
Return _value
|
|
End Get
|
|
End Property
|
|
|
|
Public Sub Destroy()
|
|
_value = String.Empty
|
|
End Sub
|
|
|
|
End Class
|
|
|
|
Public Enum JSONType
|
|
bool
|
|
int
|
|
[double]
|
|
[string]
|
|
[object]
|
|
array
|
|
null
|
|
undefined
|
|
End Enum |