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

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

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

举例:

1、读取节点数据

vbnet 复制代码
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节点,写入数据并输出文本

vbnet 复制代码
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字符串 |

源码如下:

vbnet 复制代码
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
相关推荐
轻口味3 小时前
【每日学点鸿蒙知识】私仓搭建、resources创建文件夹、hvigor如何动态设置版本、SM3摘要算法、SP存储报错等
华为·json·harmonyos
alikami1 天前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
dingdingfish1 天前
JSON 系列之1:将 JSON 数据存储在 Oracle 数据库中
oracle·json·database
糖朝1 天前
c#读取json
c#·json
dingdingfish1 天前
JSON 系列之2:JSON简单查询
oracle·json·database·19c·23ai
_oP_i2 天前
HTTP 请求Media typetext/plain application/json text/json区别
网络协议·http·json
fkdw2 天前
C# Newtonsoft.Json 反序列化派生类数据丢失问题
c#·json
Kiros_Jiang2 天前
开源低代码平台-Microi吾码 打印引擎使用
javascript·开源·json·.net·pip
nbsaas-boot3 天前
探索 JSON 数据在关系型数据库中的应用:MySQL 与 SQL Server 的对比
数据库·mysql·json
疯一样的码农3 天前
Jackson 的@JsonRawValue
json