【问题标题】:How to parse nested JSON in VB.NET the fastest and easiest way?如何以最快和最简单的方式在 VB.NET 中解析嵌套的 JSON?
【发布时间】:2019-11-29 16:46:42
【问题描述】:

我在从 JSON 对象中取出嵌套值时遇到问题。 我在谷歌上搜索并想出了一个提供“根”或者说“未嵌套”值的小解决方案。反序列化不会解析嵌套值。现在我被困住了。

Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq

JSON 文件源:

{
  "matchNumber": "222",
  "phase": "Bronze Medal Match",
  "category": {
    "name": "F-67kg",
    "gender": "FEMALE",
    "subCategory": "OLYMPIC CATEGORY",
    "bodyLevel": 22,
    "headLevel": 5
  },
  "blueAthlete": {
    "name": "playernameblue",
    "wtfId": "wtfidblue",
    "flagAbbreviation": "GER"
  },
  "blueAthleteVideoQuota": 1,
  "redAthlete": {
    "name": "playernamered",
    "wtfId": "wtfidred",
    "flagAbbreviation": "AZE"
  },
  "redAthleteVideoQuota": 1,
  "roundsConfig": {
    "rounds": 3,
    "roundTimeMinutes": 2,
    "roundTimeSeconds": 0,
    "kyeShiTimeMinutes": 1,
    "kyeShiTimeSeconds": 0,
    "restTimeMinutes": 1,
    "restTimeSeconds": 0,
    "goldenPointEnabled": true,
    "goldenPointTimeMinutes": 1,
    "goldenPointTimeSeconds": 0
  },
  "differencialScore": 20,
  "maxAllowedGamJeoms": 0,
  "paraTkdMatch": false
}

由此 JSON 生成的 VB 代码和类:

Public Class Category
    Public Property name As String
    Public Property gender As String 
    Public Property subCategory As String
    Public Property bodyLevel As String
    Public Property headLevel As String
End Class

Public Class BlueAthlete
    Public Property name As String
    Public Property wtfId As String
    Public Property flagAbbreviation As String
End Class

Public Class RedAthlete
    Public Property name As String
    Public Property wtfId As String
    Public Property flagAbbreviation As String
End Class

Public Class RoundsConfig
    Public Property rounds As Integer
    Public Property roundTimeMinutes As Integer
    Public Property roundTimeSeconds As Integer
    Public Property kyeShiTimeMinutes As Integer
    Public Property kyeShiTimeSeconds As Integer
    Public Property restTimeMinutes As Integer
    Public Property restTimeSeconds As Integer
    Public Property goldenPointEnabled As Boolean
    Public Property goldenPointTimeMinutes As Integer
    Public Property goldenPointTimeSeconds As Integer
End Class

Public Class RootObject
    Public Property matchNumber As String
    Public Property phase As String
    Public Property category As Category
    Public Property blueAthlete As BlueAthlete
    Public Property blueAthleteVideoQuota As Integer
    Public Property redAthlete As RedAthlete
    Public Property redAthleteVideoQuota As Integer
    Public Property roundsConfig As RoundsConfig
    Public Property differencialScore As Integer
    Public Property maxAllowedGamJeoms As Integer
    Public Property paraTkdMatch As Boolean
End Class

我尝试解析值的代码:

Dim rootObject As RootObject = JsonConvert.DeserializeObject(Of RootObject)(s)

String.Text = rootObject.matchNumber
String.Text = String.Text & vbCrLf & rootObject.phase

String.Text = String.Text & vbCrLf & rootObject.category.name
String.Text = String.Text & vbCrLf & rootObject.category.gender
String.Text = String.Text & vbCrLf & rootObject.category.subCategory
String.Text = String.Text & vbCrLf & rootObject.category.bodyLevel
String.Text = String.Text & vbCrLf & rootObject.category.headLevel

String.Text = String.Text & vbCrLf & rootObject.blueAthleteVideoQuota
String.Text = String.Text & vbCrLf & rootObject.redAthleteVideoQuota
String.Text = String.Text & vbCrLf & rootObject.differencialScore
String.Text = String.Text & vbCrLf & rootObject.maxAllowedGamJeoms
String.Text = String.Text & vbCrLf & rootObject.paraTkdMatch

代码返回 matchNumber 222,然后发生 System.NullReferenceException。对象未设置为对象的实例

这一行抛出异常: String.Text = String.Text & vbCrLf & rootObject.category.name

一般来说,所有更深的嵌套值都会返回该异常。

所以问题是,如何解决这个问题?

更新: 这是复制的完整代码 - 所以基本上这段代码是一个简单的服务器,通过 POST 请求检索 JSON 数据。 VAR jsonstring(从 s 重命名为 jsonstring)包含接收到的 JSON。 Richtextbox1 还包含仅用于查看收到的 JSON 的 JSON。 Richtextbox2 用于排列值。

Imports System.Threading
Imports System.Net
Imports System.Text
Imports System.IO
Imports System
Imports System.Web
Imports System.Collections.Generic
Imports System.Threading.Tasks
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Imports Newtonsoft.Json.Converters
Imports Newtonsoft.Json.Serialization

Public Class Server

#Region "VARS"
    Private listener As HttpListener
    Private mainThread As Thread
    Dim encoding As New UTF8Encoding
    Public Shared JSON_Route As String = ""
    Dim jsonstring As String = ""
#End Region

    Protected Overrides Sub OnFormClosing(ByVal e As System.Windows.Forms.FormClosingEventArgs)
        listener.Abort()
        mainThread.Join()
    End Sub

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
        mainThread = New Thread(AddressOf mainRequestLoop)
        mainThread.Start()
    End Sub

    Private Delegate Sub updateListBoxHandler(ByVal msg As String)

    Public Sub UpdateListBox(ByVal msg As String)
        If InvokeRequired Then
            Invoke(New updateListBoxHandler(AddressOf UpdateListBox), New String() {msg})
        Else
            ListBox1.Items.Add(msg)
        End If
    End Sub

    Public Class Category
        Public Property name As String
        Public Property gender As String
        Public Property subCategory As String
        Public Property bodyLevel As String
        Public Property headLevel As String
    End Class

    Public Class BlueAthlete
            Public Property name As String
            Public Property wtfId As String
            Public Property flagAbbreviation As String
        End Class

        Public Class RedAthlete
            Public Property name As String
            Public Property wtfId As String
            Public Property flagAbbreviation As String
        End Class

        Public Class RoundsConfig
            Public Property rounds As Integer
            Public Property roundTimeMinutes As Integer
            Public Property roundTimeSeconds As Integer
            Public Property kyeShiTimeMinutes As Integer
            Public Property kyeShiTimeSeconds As Integer
            Public Property restTimeMinutes As Integer
            Public Property restTimeSeconds As Integer
            Public Property goldenPointEnabled As Boolean
            Public Property goldenPointTimeMinutes As Integer
            Public Property goldenPointTimeSeconds As Integer
        End Class

        Public Class RootObject
            Public Property matchNumber As String
            Public Property phase As String
            Public Property category As Category
            Public Property blueAthlete As BlueAthlete
            Public Property blueAthleteVideoQuota As Integer
            Public Property redAthlete As RedAthlete
            Public Property redAthleteVideoQuota As Integer
            Public Property roundsConfig As RoundsConfig
            Public Property differencialScore As Integer
            Public Property maxAllowedGamJeoms As Integer
            Public Property paraTkdMatch As Boolean
        End Class

    Public Sub mainRequestLoop()
        listener = New HttpListener()
        listener.Prefixes.Add("http://localhost:" & TextBox_Port.Text & "/" & TextBox_Restfulpath.Text & "/")
        Try
            listener.Start()
        Catch ex As Exception
            MsgBox("Please start as Admin (with administration rights granted.)")
        End Try

        Try
            Do

                Dim ctx As HttpListenerContext = listener.GetContext()
                Dim worker As New HttpRequestWorker(ctx, Me)
                ' ToDo: use threadpool threads probably better
                Dim t As New Thread(AddressOf worker.ProcessRequest)
                Dim request = ctx.Request
                Dim body As Stream = request.InputStream
                Dim reader As New StreamReader(body, encoding)
                jsonstring = reader.ReadToEnd()

                Richtextbox1.Text = jsonstring

                Dim rootObject As RootObject = JsonConvert.DeserializeObject(Of RootObject)(s)

                RichTextBox2.Text = rootObject.matchNumber
                RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.phase

                RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.category.name
                RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.category.gender
                RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.category.subCategory
                RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.category.bodyLevel
                RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.category.headLevel

                RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.blueAthleteVideoQuota
                RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.redAthleteVideoQuota
                RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.differencialScore
                RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.maxAllowedGamJeoms
                RichTextBox2.Text = RichTextBox2.Text & vbCrLf & rootObject.paraTkdMatch


                t.Start()

            Loop
        Catch ex As Exception
            MsgBox(ex.ToString())
        End Try
    End Sub
    ' Http Request Handler
    Private Class HttpRequestWorker

        Private context As HttpListenerContext
        Private caller As Server

        Public Sub New(ByVal context As HttpListenerContext, ByVal f As Server)
            Me.context = context
            caller = f
        End Sub

        ' Handle the request
        Public Sub ProcessRequest()

            Dim msg As String = context.Request.HttpMethod & " " & context.Request.Url.ToString()
            JSON_Route = context.Request.Url.ToString()

            caller.UpdateListBox(msg)

            Dim url As System.Uri = context.Request.Url

            Dim path As String = url.GetComponents(UriComponents.Path, UriFormat.SafeUnescaped)
            Debug.WriteLine(path)

            Dim response As HttpListenerResponse = context.Response

            Try
                Dim requestError As Boolean
                Dim requestError1 As Boolean

                requestError = context.Request.HttpMethod.ToUpper() <> "GET" OrElse String.IsNullOrEmpty(path)
                requestError1 = context.Request.HttpMethod.ToUpper() <> "POST" OrElse String.IsNullOrEmpty(path)

                If Not requestError Then
                    response.AddHeader("Cache-Control", "no-cache")
                    response.AddHeader("Pragma", "no-cache")
                    response.StatusCode = 200

                    Dim encoding As New UTF8Encoding
                    response.ContentEncoding = encoding
                    response.ContentType = "text/html"

                    Dim responseHtml As String = "Available"
                    Dim responseHtmlBytes() As Byte = encoding.GetBytes(responseHtml)
                    response.ContentLength64 = responseHtmlBytes.Length

                    Dim stream As IO.Stream = response.OutputStream
                    stream.Write(responseHtmlBytes, 0, responseHtmlBytes.Length)
                    stream.Close()
                Else
                    response.StatusCode = 404
                End If
            Catch ex As Exception
                response.StatusCode = 500
            Finally
                response.Close()
            End Try
        End Sub
End Class

【问题讨论】:

  • 我现在可以给你一个正确的答案,但请检查我关于 JSON 主题的一些答案。使用一些可视化工具,然后写出关卡名称,想象一个 json 是一个 x 层的建筑,然后你一层一层地往上走。
  • 我找到了你的主题:stackoverflow.com/questions/56970361/… - 我会调查的。看起来很简单。如果可行,我稍后会告诉你。
  • 这是其中之一。
  • 什么是字符串?您没有将字符串变量命名为 String,对吗?是文本框吗?如果是文本框,不要一遍遍更新UI;这是很多屏幕重绘。在代码中构建一个字符串,最后设置文本框的文本属性一次。
  • 我无法重现您的问题。您的代码不会按原样编译,因为未定义 String.Text。如果我将String.Text 更改为局部变量Dim Text = rootObject.matchNumber,那么您的代码将成功运行而没有任何错误:dotnetfiddle.net/FEM4h8。你能请edit你的问题分享minimal reproducible example吗?

标签: json vb.net object json.net deserialization


【解决方案1】:

请检查你做错了什么,在我的两端都可以正常工作。

Imports System.Reflection
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq

Public Class Form1

    Public Class Category
        Public Property name As String
        Public Property gender As String
        Public Property subCategory As String
        Public Property bodyLevel As Integer
        Public Property headLevel As Integer
    End Class

    Public Class BlueAthlete
        Public Property name As String
        Public Property wtfId As String
        Public Property flagAbbreviation As String
    End Class

    Public Class RedAthlete
        Public Property name As String
        Public Property wtfId As String
        Public Property flagAbbreviation As String
    End Class

    Public Class RoundsConfig
        Public Property rounds As Integer
        Public Property roundTimeMinutes As Integer
        Public Property roundTimeSeconds As Integer
        Public Property kyeShiTimeMinutes As Integer
        Public Property kyeShiTimeSeconds As Integer
        Public Property restTimeMinutes As Integer
        Public Property restTimeSeconds As Integer
        Public Property goldenPointEnabled As Boolean
        Public Property goldenPointTimeMinutes As Integer
        Public Property goldenPointTimeSeconds As Integer
    End Class

    Public Class Example
        Public Property matchNumber As String
        Public Property phase As String
        Public Property category As Category
        Public Property blueAthlete As BlueAthlete
        Public Property blueAthleteVideoQuota As Integer
        Public Property redAthlete As RedAthlete
        Public Property redAthleteVideoQuota As Integer
        Public Property roundsConfig As RoundsConfig
        Public Property differencialScore As Integer
        Public Property maxAllowedGamJeoms As Integer
        Public Property paraTkdMatch As Boolean
    End Class

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim Something As JObject = JObject.Parse(TextBox1.Text)
        Debug.Print(String.Format("I {0} want {1} this {2}", Something("category")("name").ToString, Something("category")("gender").ToString, Something("category")("bodyLevel").ToString))
' I F-67kg want FEMALE this 22
        Dim testing As Example = JsonConvert.DeserializeObject(Of Example)(TextBox1.Text)
        Debug.Print(String.Format("I {0} want {1} this {2}", testing.category.name, testing.category.gender, testing.category.bodyLevel))
' I F-67kg want FEMALE this 22


    TextBox2.AppendText(testing.matchNumber & vbNewLine)
    TextBox2.AppendText(testing.phase & vbNewLine)
    TextBox2.AppendText(testing.category.name & vbNewLine)
    TextBox2.AppendText(testing.category.gender & vbNewLine)
    TextBox2.AppendText(testing.category.subCategory & vbNewLine)
    TextBox2.AppendText(testing.category.bodyLevel & vbNewLine)
    TextBox2.AppendText(testing.category.headLevel & vbNewLine)
    TextBox2.AppendText(testing.blueAthleteVideoQuota & vbNewLine)
    TextBox2.AppendText(testing.redAthleteVideoQuota & vbNewLine)
    TextBox2.AppendText(testing.differencialScore & vbNewLine)
    TextBox2.AppendText(testing.maxAllowedGamJeoms & vbNewLine)
    TextBox2.AppendText(testing.paraTkdMatch & vbNewLine)

    For Each item As PropertyInfo In testing.GetType.GetProperties()
        If item.PropertyType.IsNested Then

            Dim TypeHolder as Type = item.GetValue(testing)
            For Each subitem As PropertyInfo In TypeHolder.GetType.GetProperties()
                TextBox3.AppendText(subitem.Name & ": " & subitem.GetValue(TypeHolder).ToString & vbNewLine)
            Next

        Else
            TextBox3.AppendText(item.Name & ": " & item.GetValue(testing).ToString & vbNewLine)
        End If
    Next
    End Sub
End Class

【讨论】:

    猜你喜欢
    • 2016-03-28
    • 1970-01-01
    • 2011-06-21
    • 2023-03-25
    • 2011-05-09
    • 1970-01-01
    • 2016-03-06
    • 1970-01-01
    • 2011-08-22
    相关资源
    最近更新 更多