【vb.net】轻量JSON序列及反序列化

这个代码写的有点时间了,可能有点小bug,欢迎评论区反馈

作用是将Json文本转化成一个HarryNode类进行相关的Json对象处理或者读取,也可以将一个HarryNode对象用ToString变为Json文本。

举例:

1、读取节点数据

dim harryNode = New HarryNode("", "{""msg"":""hello world!""}")
msgbox(harryNode.GetAtt("msg")) '弹窗显示hello world!


'下面展示更复杂的嵌套读取
dim harryNode = New HarryNode("", "{""node1"": {""msg"":""hello world!""}}")
msgbox(harryNode.GetAtt("node1.msg")) '弹窗显示hello world! 没错,用“.”作为路径连接符进行寻址

'如果json的键里包含“.”可以将源码里的“.”替换成其它字符,也可以这样进行取值
msgbox(harryNode.GetAtt("node1")("msg").value
'这里的harryNode.GetAtt("node1")返回的是一个字典对象(String, HarryNode)

2、创建新Json节点,写入数据并输出文本

Dim harryNode = New HarryNode("", "{}")
harryNode.SetAtt("msg", """hello world!""")
MsgBox(harryNode.ToString)

'可以看到SetAtt方法的第二个参数输入的字符串需要是json字符串格式,因此字符串本身需要加双引号
'下面可以用SetAtt的另一种重载方法,与上面代码的结果相同
harryNode.SetAtt("msg", "hello world!", NodeTypeEnum.isString)
MsgBox(harryNode.ToString)

'同样,对嵌套的复杂json对象,可以如下
harryNode.SetAtt("node1.msg", "hello world!", NodeTypeEnum.isString)
'下面这样写也是可以的
harryNode.SetAtt("node1", "{""msg"": ""hello world!""}")

文档

1、方法和函数

New

构造函数

name String 节点的名字(对于根节点此项没啥意义)
json String 要解析构造的JSON串
parent HarryNode 实例的父节点
name String 节点的名字(对于根节点此项没啥意义)
nodeValue Object 节点VB.NET对象值
type NodeTypeEnum 节点值的类型
parent HarryNode 实例的父节点

GetAtt

获得指定路径的VB.NET对象

path String 节点路径
defaultValue Object 没有获取到返回的值,默认Nothing

SetAtt

根据指定路径设置节点值

path String 节点路径
newValue Object 节点的值(VB.NET对象)
newValueType NodeTypeEnum 值的类型

path String 节点路径
json String 节点的值(JSON字符串)

ReName

重命名某个节点

path String 节点路径
newName String 新名字

ToJson

返回JSON字符串,与ToString()等价

GetNode

获得指定路径的HarryNode对象

path String 节点路径

AddNode

添加子节点

path String 节点路径
nodeName String 子节点名
nodeJson String 子节点JSON串

Del

删除指定路径的节点

path String 节点路径

Merge

合并两个字典节点;

node HarryNode 要合并的节点

GetChildPath

返回一个当前节点子节点名的列表

Add

指定某个节点的数据加一个值

path String 节点路径
addValue Single 加数

ConAdd

指定某个节点的数据加一个值,但是限制了数的范围

path String 节点路径
addValue Single 加数
maxValue Single 最大值
minValue Single 最小值,默认0

Mul

指定某个节点的数据乘一个值

path String 节点路径
addValue Single 乘数

Power

指定某个节点的数据求次幂

path String 节点路径
addValue Single

2、属性

Value

当前节点的VB.NET类型值

3、事件

NodeContentChangeBefore

节点内容改变之前

path String 节点路径
newValue Object 即将变成的值
newValueType NodeTypeEnum 即将变成值的类型

NodeContentChangeBeforeFromJson

节点内容改变之前(通过JSON解释)

path String 节点路径
json String 即将变成的值的JSON字符串

NodeContentChangeLater

节点内容改变之后

path String 节点路径
newValue Object 变成的值
newValueType NodeTypeEnum 变成值的类型

NodeContentChangeLaterFromJson

节点内容改变之后(通过JSON解释)

path String 节点路径
json String 变成的值的JSON字符串

源码如下:

Imports System.Text.RegularExpressions
Public Class HarryNode
    Public Shared pathSeparator As String = "."
    Public Shared outputFormat As Boolean = True
    Public Shared formatRetraction As Integer = 2
    Public Shared Function MulReplace(source As String, ParamArray args() As String) As String
        If args.Length Mod 2 <> 0 Then
            Return source
        End If
        For i As Integer = 0 To UBound(args) Step 2
            source = Replace(source, args(i), args(i + 1))
        Next
        Return source
    End Function
    Public Shared Function ToEscape(source As String) As String
        Return MulReplace(source, "\", "\\", vbCrLf, "\n", vbTab, "\t", """", "\""", Chr(8), "\b", Chr(12), "\f")
    End Function
    Public Enum NodeTypeEnum
        isNull = 0
        isString = 1
        isSingle = 2
        isDict = 3
        isList = 4
        isBool = 5
    End Enum
    Public nodeType As NodeTypeEnum
    Public nodeName As String
    Public parentNode As HarryNode

    Private stringValue As String
    Private singleValue As Single
    Private boolValue As Boolean
    Private childNode As Dictionary(Of String, HarryNode)

    Public Event NodeContentChangeBefore(ByRef path As String, ByRef newValue As Object, ByRef newValueType As String)
    Public Event NodeContentChangeBeforeFromJson(ByRef path As String, ByRef json As String)

    Public Event NodeContentChangeLater(path As String, ByRef nowValue As Object, ByRef newValueType As NodeTypeEnum)
    Public Event NodeContentChangeLaterFromJson(path As String, nowJson As String)
    Public Sub Merge(node As HarryNode)
        If nodeType = node.nodeType And nodeType = NodeTypeEnum.isDict Then
            For i = 0 To node.childNode.Count - 1
                Dim key = node.childNode.Keys(i)
                If childNode.ContainsKey(key) Then
                    childNode(key).Merge(node.childNode(key))
                Else
                    childNode.Add(key, node.childNode(key))
                End If
            Next
        End If
    End Sub
    Public Function GetChildPath() As List(Of String)
        Dim result As New List(Of String)
        If nodeType = NodeTypeEnum.isDict Or nodeType = NodeTypeEnum.isList Then
            result.AddRange(childNode.Keys)
        Else
            result.Add(nodeName)
        End If
        Return result
    End Function
    'Public Function GetTreeNode(interpreter As 解释器) As TreeNode
    '    Dim rootNode As New TreeNode(nodeName & interpreter.Search(nodeName))
    '    If nodeType = NodeTypeEnum.isDict Or nodeType = NodeTypeEnum.isList Then
    '        For Each cNode In childNode
    '            rootNode.Nodes.Add(cNode.Value.GetTreeNode(interpreter))
    '        Next
    '    Else
    '        rootNode.Nodes.Add(Value & interpreter.Search(Value))
    '    End If
    '    Return rootNode
    'End Function
    Public Sub Power(path As String, addValue As Single)
        SetAtt(path, GetAtt(path, 0) ^ addValue, 0)
    End Sub
    Public Sub Add(path As String, addValue As Single)
        SetAtt(path, GetAtt(path, 0) + addValue, 0)
    End Sub
    Public Sub ConAdd(path As String, addValue As Single, maxValue As Single, Optional minValue As Single = 0)
        Dim newValue As Single = GetAtt(path, 0) + addValue
        If newValue > maxValue Then
            newValue = maxValue
        End If
        If newValue < minValue Then
            newValue = minValue
        End If
        SetAtt(path, newValue, 0)
    End Sub
    Public Sub Mul(path As String, addValue As Single)
        SetAtt(path, GetAtt(path, 0) * addValue, 0)
    End Sub
    Public Sub AddNode(path As String, nodeName As String, nodeJson As String)
        Dim paths() As String = path.Split(pathSeparator)
        Dim p As String
        Dim node As HarryNode = Me
        For i As Integer = 0 To UBound(paths) - 1
            p = paths(i)
            Select Case node.nodeType
                Case NodeTypeEnum.isDict, NodeTypeEnum.isList
                    If node.nodeType = NodeTypeEnum.isList Then
                        p = Int(Val(p))
                    End If
                    If Not node.childNode.ContainsKey(p) Then
                        node.childNode.Add(p, New HarryNode(p, "{}", Me))
                    End If
                Case Else
                    node.nodeType = NodeTypeEnum.isDict
                    node.childNode = New Dictionary(Of String, HarryNode)
                    If Not node.childNode.ContainsKey(p) Then
                        node.childNode.Add(p, New HarryNode(p, "{}", Me))
                    End If
            End Select
            node = node.childNode(p)
        Next
        p = paths.Last
        Select Case node.nodeType
            Case NodeTypeEnum.isDict, NodeTypeEnum.isList
                If node.nodeType = NodeTypeEnum.isList Then
                    p = Int(Val(p))
                End If
                If Not node.childNode.ContainsKey(p) Then
                    node.childNode.Add(p, New HarryNode(p, "{}", Me))
                End If
            Case Else
                node.nodeType = NodeTypeEnum.isDict
                node.childNode = New Dictionary(Of String, HarryNode)
                If Not node.childNode.ContainsKey(p) Then
                    node.childNode.Add(p, New HarryNode(p, "{}", Me))
                End If
        End Select
        If Not node.childNode.ContainsKey(p) Then
            node.childNode.Add(p, New HarryNode(nodeName, nodeJson, Me))
        Else
            node.childNode(p) = New HarryNode(nodeName, nodeJson, Me)
        End If
    End Sub
    Public Sub Del(path As String)
        Dim paths() As String = path.Split(pathSeparator)
        Dim p As String
        Dim node As HarryNode = Me
        For i As Integer = 0 To UBound(paths) - 1
            p = paths(i)
            Select Case node.nodeType
                Case NodeTypeEnum.isDict, NodeTypeEnum.isList
                    If node.nodeType = NodeTypeEnum.isList Then
                        p = Int(Val(p))
                    End If
                    If Not node.childNode.ContainsKey(p) Then
                        Return
                    End If
                Case Else
                    node.nodeType = NodeTypeEnum.isDict
                    node.childNode = New Dictionary(Of String, HarryNode)
                    If Not node.childNode.ContainsKey(p) Then
                        Return
                    End If
            End Select
            node = node.childNode(p)
        Next
        p = paths.Last
        Select Case node.nodeType
            Case NodeTypeEnum.isDict, NodeTypeEnum.isList
                If node.nodeType = NodeTypeEnum.isList Then
                    p = Int(Val(p))
                End If
                If Not node.childNode.ContainsKey(p) Then
                    Return
                End If
            Case Else
                node.nodeType = NodeTypeEnum.isDict
                node.childNode = New Dictionary(Of String, HarryNode)
                If Not node.childNode.ContainsKey(p) Then
                    Return
                End If
        End Select
        node.childNode.Remove(p)
    End Sub
    Public Function GetAtt(path As String, Optional defaultValue As Object = Nothing) As Object
        If path = "" Then
            Return Value
        End If
        Dim paths() As String = path.Split(pathSeparator)
        Dim node As HarryNode = Me
        For Each p As String In paths
            Select Case node.nodeType
                Case NodeTypeEnum.isDict, NodeTypeEnum.isList
                    If node.childNode.ContainsKey(p) Then
                        node = node.childNode(p)
                    Else
                        Return defaultValue
                    End If
                Case Else
                    Return defaultValue
            End Select
        Next
        Return node.Value
    End Function
    Public Function GetNode(path As String) As HarryNode
        If path = "" Then
            Return Me
        End If
        Dim p As String
        Dim paths() As String = path.Split(pathSeparator)
        Dim node As HarryNode = Me
        For i As Integer = 0 To UBound(paths) - 1
            p = paths(i)
            Select Case node.nodeType
                Case NodeTypeEnum.isDict, NodeTypeEnum.isList
                    If node.childNode.ContainsKey(p) Then
                        node = node.childNode(p)
                    Else
                        Return New HarryNode("", "", Me)
                    End If
                Case Else
                    Return New HarryNode("", "", Me)
            End Select
        Next
        If node.childNode IsNot Nothing AndAlso node.childNode.ContainsKey(paths.Last) Then
            Return node.childNode(paths.Last)
        End If
        Return New HarryNode(paths.Last, String.Format("""{0}""", paths.Last), Me)
    End Function
    Public Sub SetAtt(path As String, newValue As Object, newValueType As String)
        RaiseEvent NodeContentChangeBefore(path, newValue, newValueType)
        Dim paths() As String = path.Split(pathSeparator)
        Dim p As String
        Dim node As HarryNode = Me
        For i As Integer = 0 To UBound(paths) - 1
            p = paths(i)
            Select Case node.nodeType
                Case NodeTypeEnum.isDict, NodeTypeEnum.isList
                    If node.nodeType = NodeTypeEnum.isList Then
                        p = Int(Val(p))
                    End If
                    If Not node.childNode.ContainsKey(p) Then
                        node.childNode.Add(p, New HarryNode(p, "{}", Me))
                    End If
                Case Else
                    node.nodeType = NodeTypeEnum.isDict
                    node.childNode = New Dictionary(Of String, HarryNode)
                    If Not node.childNode.ContainsKey(p) Then
                        node.childNode.Add(p, New HarryNode(p, "{}", Me))
                    End If
            End Select
            node = node.childNode(p)
        Next
        p = paths.Last
        Select Case node.nodeType
            Case NodeTypeEnum.isDict, NodeTypeEnum.isList
                If node.nodeType = NodeTypeEnum.isList Then
                    p = Int(Val(p))
                End If
                If Not node.childNode.ContainsKey(p) Then
                    node.childNode.Add(p, New HarryNode(p, newValue, newValueType, Me))
                End If
            Case Else
                node.nodeType = NodeTypeEnum.isDict
                node.childNode = New Dictionary(Of String, HarryNode)
                If Not node.childNode.ContainsKey(p) Then
                    node.childNode.Add(p, New HarryNode(p, newValue, newValueType, Me))
                End If
        End Select
        node.childNode(p).Value = newValue
        RaiseEvent NodeContentChangeLater(path, node.childNode(p).Value, node.nodeType)
    End Sub
    Public Sub ReName(path As String, newName As String)
        Dim paths() As String = path.Split(pathSeparator)
        Dim p As String
        Dim node As HarryNode = Me
        For i As Integer = 0 To UBound(paths) - 1
            p = paths(i)
            Select Case node.nodeType
                Case NodeTypeEnum.isDict, NodeTypeEnum.isList
                    If node.nodeType = NodeTypeEnum.isList Then
                        p = Int(Val(p))
                    End If
                    If Not node.childNode.ContainsKey(p) Then
                        node.childNode.Add(p, New HarryNode(p, "{}", Me))
                    End If
                Case Else
                    node.nodeType = NodeTypeEnum.isDict
                    node.childNode = New Dictionary(Of String, HarryNode)
                    If Not node.childNode.ContainsKey(p) Then
                        node.childNode.Add(p, New HarryNode(p, "{}", Me))
                    End If
            End Select
            node = node.childNode(p)
        Next
        p = paths.Last
        Select Case node.nodeType
            Case NodeTypeEnum.isDict, NodeTypeEnum.isList
                If node.nodeType = NodeTypeEnum.isList Then
                    p = Int(Val(p))
                End If
                If node.childNode.ContainsKey(p) Then
                    ' 修改
                    node.childNode.Add(newName, New HarryNode(newName, node.childNode(p).ToJson, Me))
                    node.childNode.Remove(p)
                End If
            Case Else
                node.nodeType = NodeTypeEnum.isDict
                node.childNode = New Dictionary(Of String, HarryNode)
                If node.childNode.ContainsKey(p) Then
                    node.childNode.Add(newName, New HarryNode(newName, node.childNode(p).ToJson, Me))
                    node.childNode.Remove(p)
                End If
        End Select
    End Sub
    Public Sub SetAtt(path As String, json As String)
        RaiseEvent NodeContentChangeBeforeFromJson(path, json)
        Dim paths() As String = path.Split(pathSeparator)
        Dim p As String
        Dim node As HarryNode = Me
        For i As Integer = 0 To UBound(paths) - 1
            p = paths(i)
            Select Case node.nodeType
                Case NodeTypeEnum.isDict, NodeTypeEnum.isList
                    If node.nodeType = NodeTypeEnum.isList Then
                        p = Int(Val(p))
                    End If
                    If Not node.childNode.ContainsKey(p) Then
                        node.childNode.Add(p, New HarryNode(p, "{}", Me))
                    End If
                Case Else
                    node.nodeType = NodeTypeEnum.isDict
                    node.childNode = New Dictionary(Of String, HarryNode)
                    If Not node.childNode.ContainsKey(p) Then
                        node.childNode.Add(p, New HarryNode(p, "{}", Me))
                    End If
            End Select
            node = node.childNode(p)
        Next
        p = paths.Last
        Select Case node.nodeType
            Case NodeTypeEnum.isDict, NodeTypeEnum.isList
                If node.nodeType = NodeTypeEnum.isList Then
                    p = Int(Val(p))
                End If
                If Not node.childNode.ContainsKey(p) Then
                    node.childNode.Add(p, New HarryNode(p, "{}", Me))
                End If
            Case Else
                node.nodeType = NodeTypeEnum.isDict
                node.childNode = New Dictionary(Of String, HarryNode)
                If Not node.childNode.ContainsKey(p) Then
                    node.childNode.Add(p, New HarryNode(p, "{}", Me))
                End If
        End Select
        node.childNode(p).JsonToValue(json)
        RaiseEvent NodeContentChangeLaterFromJson(path, json)
    End Sub
    Public Function ToJson(Optional deep As Integer = 1) As String
        If outputFormat Then
            Dim deepFormatRetraction = New String(" ", deep * formatRetraction)
            Dim deepFormatRetractionSub1 = New String(" ", (deep - 1) * formatRetraction)
            Select Case nodeType
                Case NodeTypeEnum.isString
                    Return String.Format("""{0}""", ToEscape(stringValue))
                Case NodeTypeEnum.isBool
                    Return boolValue.ToString.ToLower
                Case NodeTypeEnum.isSingle
                    Return singleValue
                Case NodeTypeEnum.isDict
                    Dim result As New List(Of String)
                    For i As Integer = 0 To childNode.Count - 1
                        result.Add(String.Format(deepFormatRetraction & """{0}"": {1}", childNode.Keys(i), childNode.Values(i).ToJson(deep + 1)))
                    Next
                    Return String.Format(Replace("{{\n{0}\n{1}}}", "\n", vbCrLf), Join(result.ToArray, "," & vbCrLf), deepFormatRetractionSub1)
                Case NodeTypeEnum.isList
                    Dim result As New List(Of String)
                    For i As Integer = 0 To childNode.Count - 1
                        result.Add(deepFormatRetraction & childNode.Values(i).ToJson(deep + 1))
                    Next
                    Return String.Format(Replace("[\n{0}\n{1}]", "\n", vbCrLf), Join(result.ToArray, "," & vbCrLf), deepFormatRetractionSub1)
                Case Else
                    Return ""
            End Select
        End If
        Select Case nodeType
            Case NodeTypeEnum.isString
                Return String.Format("""{0}""", ToEscape(stringValue))
            Case NodeTypeEnum.isBool
                Return boolValue
            Case NodeTypeEnum.isSingle
                Return singleValue
            Case NodeTypeEnum.isDict
                Dim result As New List(Of String)
                For i As Integer = 0 To childNode.Count - 1
                    result.Add(String.Format("""{0}"":{1}", childNode.Keys(i), childNode.Values(i).ToJson))
                Next
                Return String.Format("{{{0}}}", Join(result.ToArray, ","))
            Case NodeTypeEnum.isList
                Dim result As New List(Of String)
                For i As Integer = 0 To childNode.Count - 1
                    result.Add(childNode.Values(i).ToJson)
                Next
                Return String.Format("[{0}]", Join(result.ToArray, ","))
            Case Else
                Return ""
        End Select
    End Function
    Public Overloads Function ToString() As String
        Return ToJson()
    End Function
    Public Property Value() As Object
        Get
            Select Case nodeType
                Case NodeTypeEnum.isString
                    Return stringValue
                Case NodeTypeEnum.isBool
                    Return boolValue
                Case NodeTypeEnum.isSingle
                    Return singleValue
                Case NodeTypeEnum.isDict
                    Return childNode
                Case NodeTypeEnum.isList
                    Return childNode.Values
                Case Else
                    Return Nothing
            End Select
        End Get
        Set(value As Object)
            Select Case nodeType
                Case NodeTypeEnum.isString
                    stringValue = value
                Case NodeTypeEnum.isBool
                    boolValue = value
                Case NodeTypeEnum.isSingle
                    singleValue = value
                Case NodeTypeEnum.isDict
                    childNode = value
                Case NodeTypeEnum.isList
                    Dim valueList As List(Of HarryNode) = value
                    childNode.Clear()
                    For i As Integer = 0 To valueList.Count - 1
                        childNode.Add(i, valueList(i))
                    Next
            End Select
        End Set
    End Property
    Public Sub JsonToValue(json As String)
        If json Is Nothing Then
            Return
        End If
        json = Regex.Match(json, "^\s*(.*?)\s*$", RegexOptions.Singleline).Groups(1).Value
        If Regex.IsMatch(json, "^"".*""$", RegexOptions.Singleline) Then
            '字符串
            nodeType = NodeTypeEnum.isString
            stringValue = json.Substring(1, json.Length - 2)
        ElseIf Regex.IsMatch(json, "^{.*}$", RegexOptions.Singleline) Then
            '字典
            nodeType = NodeTypeEnum.isDict
            If json = "{}" OrElse Regex.IsMatch(json, "^\s*\{\s*\}\s*$") Then
                childNode = New Dictionary(Of String, HarryNode)
            Else
                childNode = GetDict(json, Me)
            End If
        ElseIf Regex.IsMatch(json, "^\[.*\]$", RegexOptions.Singleline) Then
            '列表
            nodeType = NodeTypeEnum.isList
            If json = "[]" OrElse Regex.IsMatch(json, "^\s*\[\s*\]\s*$") Then
                childNode = New Dictionary(Of String, HarryNode)
            Else
                childNode = GetList(json, Me)
            End If
        ElseIf Regex.IsMatch(json, "^[-]{0,1}[\d]*[\.]{0,1}[\d]*$", RegexOptions.Singleline) Then
            '数值
            nodeType = NodeTypeEnum.isSingle
            singleValue = Val(json)
        Else
            '布尔值
            nodeType = NodeTypeEnum.isBool
            boolValue = GetBool(json)
        End If
    End Sub
    Public Shared Function GetDict(json As String, sourceNode As HarryNode) As Dictionary(Of String, HarryNode)
        'Debug.WriteLine(String.Format("GetDict.json={0}", json))
        Dim node As New Dictionary(Of String, HarryNode)
        Dim name As String = ""
        Dim temp As New List(Of String)
        Dim bigBrackets As Integer
        Dim colon As Integer
        Dim doubleQuotationMark As Integer
        Dim brackets As Integer
        Dim escape As Integer
        Dim stringContent As String
        Dim exegesis As Integer
        For Each c As String In json
            'Debug.WriteLine(Join(temp.ToArray, ""))
            'Debug.WriteLine("doubleQuotationMark={0}", doubleQuotationMark)
            'Debug.WriteLine("exegesis={0}", exegesis)
            'Debug.WriteLine("bigBrackets={0}", bigBrackets)
            'Debug.WriteLine("brackets={0}", brackets)
            'Debug.WriteLine("")
            If c = "/" Then
                exegesis += 1
                Continue For
            ElseIf exegesis = 1 Then
                temp.Add("/")
                exegesis = 0
            End If
            If exegesis >= 2 Then
                If c = vbCr Or c = vbLf Then
                    exegesis = 0
                Else
                    Continue For
                End If
            End If
            If doubleQuotationMark = 0 Then
                '未在字符串内时
                Select Case c
                    Case "{"
                        bigBrackets += 1
                        If bigBrackets > 1 OrElse brackets > 0 Then
                            '子嵌套记忆
                            temp.Add(c)
                        End If
                    Case "}"
                        bigBrackets -= 1
                        If bigBrackets > 1 OrElse brackets > 0 OrElse (bigBrackets = 1 AndAlso brackets = 0) Then
                            temp.Add(c)
                        End If
                    Case "["
                        brackets += 1
                        temp.Add(c)
                    Case "]"
                        brackets -= 1
                        temp.Add(c)
                    Case ":"
                        If bigBrackets = 1 AndAlso brackets = 0 Then
                            '第一层嵌套内
                            colon += 1
                        ElseIf bigBrackets > 1 OrElse brackets > 0 Then
                            temp.Add(c)
                        End If
                    Case """"
                        If bigBrackets = 1 AndAlso brackets = 0 Then
                            '第一层嵌套内
                            doubleQuotationMark += 1
                            temp.Add(c)
                        ElseIf bigBrackets > 1 OrElse brackets > 0 Then
                            temp.Add(c)
                        End If
                    Case ","
                        If colon > 0 AndAlso bigBrackets = 1 AndAlso brackets = 0 Then
                            '非字符串
                            If temp.Count > 0 Then
                                stringContent = Join(temp.ToArray, "")
                                temp.Clear()
                                node.Add(name, New HarryNode(name, stringContent, sourceNode))
                            Else
                                'null
                                node.Add(name, New HarryNode(name, Nothing, sourceNode))
                            End If
                            colon = 0
                        Else
                            temp.Add(c)
                        End If
                    Case Else
                        If bigBrackets > 1 Or Regex.IsMatch(c, "\S", RegexOptions.Singleline) Then
                            temp.Add(c)
                        End If
                End Select
            ElseIf bigBrackets = 1 AndAlso brackets = 0 Then
                '第一层嵌套内
                '在字符串内
                Select Case c
                    Case """"
                        temp.Add(c)
                        If escape = 1 Then
                            '转义"
                            escape = 0
                        Else
                            doubleQuotationMark = 0
                            If colon = 0 Then
                                '节点名
                                stringContent = Join(temp.ToArray, "")
                                temp.Clear()
                                name = stringContent.Substring(1, stringContent.Length - 2)
                            End If
                        End If
                    Case "\"
                        escape += 1
                        If escape > 1 Then
                            '转义\
                            temp.Add(c)
                            escape = 0
                        End If
                    Case "n"
                        If escape = 1 Then
                            '转义换行
                            temp.Add(vbCrLf)
                            escape = 0
                        Else
                            temp.Add(c)
                        End If
                    Case "b"
                        If escape = 1 Then
                            temp.Add(Chr(8))
                            escape = 0
                        Else
                            temp.Add(c)
                        End If
                    Case "f"
                        If escape = 1 Then
                            temp.Add(Chr(12))
                            escape = 0
                        Else
                            temp.Add(c)
                        End If
                    Case "t"
                        If escape = 1 Then
                            temp.Add(vbTab)
                            escape = 0
                        Else
                            temp.Add(c)
                        End If
                    Case Else
                        escape = 0
                        temp.Add(c)
                End Select
            End If
        Next
        If temp.Count > 0 Then
            stringContent = Join(temp.ToArray, "")
            temp.Clear()
            node.Add(name, New HarryNode(name, stringContent, sourceNode))
        Else
            'null
            node.Add(name, New HarryNode(name, Nothing, sourceNode))
        End If
        Return node
    End Function
    Public Shared Function GetList(json As String, sourceNode As HarryNode) As Dictionary(Of String, HarryNode)
        'Debug.WriteLine(String.Format("GetList.json={0}", json))
        Dim node As New Dictionary(Of String, HarryNode)
        Dim name As String
        Dim temp As New List(Of String)
        Dim bigBrackets As Integer
        Dim doubleQuotationMark As Integer
        Dim brackets As Integer
        Dim escape As Integer
        Dim comma As Integer
        Dim stringContent As String
        For Each c As String In json
            Dim exegesis As Integer
            If c = "/" Then
                exegesis += 1
                Continue For
            ElseIf exegesis = 1 Then
                temp.Add("/")
                exegesis = 0
            End If
            If exegesis >= 2 Then
                If c = vbCr Or c = vbLf Then
                    exegesis = 0
                Else
                    Continue For
                End If
            End If
            If doubleQuotationMark = 0 Then
                '未在字符串内时
                Select Case c
                    Case "["
                        brackets += 1
                        If brackets > 1 OrElse bigBrackets > 0 Then
                            '子嵌套记忆
                            temp.Add(c)
                        End If
                    Case "]"
                        brackets -= 1
                        If brackets > 1 OrElse bigBrackets > 0 OrElse (brackets = 1 AndAlso bigBrackets = 0) Then
                            temp.Add(c)
                        End If
                    Case "{"
                        bigBrackets += 1
                        temp.Add(c)
                    Case "}"
                        bigBrackets -= 1
                        temp.Add(c)
                    Case """"
                        If brackets = 1 AndAlso bigBrackets = 0 Then
                            '第一层嵌套内
                            doubleQuotationMark += 1
                            temp.Add(c)
                        ElseIf brackets > 1 OrElse bigBrackets > 0 Then
                            temp.Add(c)
                        End If
                    Case ","
                        If bigBrackets = 0 AndAlso brackets = 1 Then
                            name = comma
                            comma += 1
                            If temp.Count > 0 Then
                                stringContent = Join(temp.ToArray, "")
                                temp.Clear()
                                node.Add(name, New HarryNode(name, stringContent, sourceNode))
                            Else
                                'null
                                node.Add(name, New HarryNode(name, Nothing, sourceNode))
                            End If
                        Else
                            temp.Add(c)
                        End If
                    Case Else
                        If bigBrackets > 1 Or Regex.IsMatch(c, "\S", RegexOptions.Singleline) Then
                            temp.Add(c)
                        End If
                End Select
            ElseIf brackets = 1 AndAlso bigBrackets = 0 Then
                '第一层嵌套内
                '在字符串内
                Select Case c
                    Case """"
                        temp.Add(c)
                        If escape = 1 Then
                            '转义"
                            escape = 0
                        Else
                            doubleQuotationMark = 0
                        End If
                    Case "\"
                        escape += 1
                        If escape > 1 Then
                            '转义\
                            temp.Add(c)
                            escape = 0
                        End If
                    Case "n"
                        If escape = 1 Then
                            '转义换行
                            temp.Add(vbCrLf)
                            escape = 0
                        Else
                            temp.Add(c)
                        End If
                    Case "b"
                        If escape = 1 Then
                            temp.Add(Chr(8))
                            escape = 0
                        Else
                            temp.Add(c)
                        End If
                    Case "f"
                        If escape = 1 Then
                            temp.Add(Chr(12))
                            escape = 0
                        Else
                            temp.Add(c)
                        End If
                    Case "t"
                        If escape = 1 Then
                            temp.Add(vbTab)
                            escape = 0
                        Else
                            temp.Add(c)
                        End If
                    Case Else
                        escape = 0
                        temp.Add(c)
                End Select
            End If
        Next
        name = comma
        If temp.Count > 0 Then
            '非字符串
            stringContent = Join(temp.ToArray, "")
            temp.Clear()
            node.Add(name, New HarryNode(name, stringContent, sourceNode))
        Else
            'null
            node.Add(name, New HarryNode(name, Nothing, sourceNode))
        End If
        Return node
    End Function
    Public Shared Function GetBool(value As String) As Boolean
        If value.ToLower = "false" OrElse value = "0" Then
            Return False
        End If
        Return True
    End Function
    Public Sub New(name As String, json As String, Optional parent As HarryNode = Nothing)
        nodeName = name
        parentNode = parent
        JsonToValue(json)
    End Sub
    Public Sub New(name As String, nodeValue As Object, type As NodeTypeEnum, Optional parent As HarryNode = Nothing)
        nodeName = name
        nodeType = type
        parentNode = parent
        Value = nodeValue
    End Sub
End Class

你可能感兴趣的:(VB遇到的那些事,json)