使用可变字段名称和值类型转换JSON结果

时间:2018-12-13 21:02:43

标签: json vb.net

我正在尝试将以下JSON示例转换为vb.net类,或者只是简单地读取信息。我可以得到第一部分IDnameobjCode,但是我不能解析parameterValues,因为列名中有空格。因此,我无法将类字段名称分配为[DE:App code]。这来自自定义模板,因此字段名称可以称为任何名称。我需要遍历所有parameterValues并获取名称和值,以便可以将它们添加到数据库中。我需要的主要值(永远存在)是IDDE:App CodeDE:App Alloc 1 Code

{
  "data": [
    {
      "ID": 43545325253,
      "name": "FY1955: PAT",
      "objCode": "PROJ",
      "parameterValues": {
        "DE:": "PS12",
        "DE:Please Enter Requested": "/rss55.edu",
        "DE:URL Allocation 1": "Society Scholarship",
        "DE:Is this being created for other purposes?": "no",
        "DE:Request Submitted by": "urser55",
        "DE:Project Owner": "Admin User",
        "DE:App Code": "YDAR",
        "DE:App Completion Date": "2018-12-14",
        "DE:App Alloc 1 Code": "SBDRC"
      }
    }
  ]
}

有人对我如何解决这个问题有任何想法吗?如果您可以提供任何VB.Net示例代码,那就太好了。


似乎要求已经改变。他们在参数中添加了另一个子片段,这使我的代码在“ DE:App Units”上崩溃了。这是JSON现在的样子:

{
  "data": [
    {
      "ID": 43545325253,
      "name": "FY1955: PAT",
      "objCode": "PROJ",
      "parameterValues": {
        "DE:": "PS12",
        "DE:Please Enter Requested": "/rss55.edu",
        "DE:URL Allocation 1": "Society Scholarship",
        "DE:Is this being created for other purposes?": "no",
        "DE:Request Submitted by": "urser55",
        "DE:Project Owner": "Admin User",
        "DE:App Code": "YDAR",
        "DE:App Completion Date": "2018-12-14",
        "DE:App Units": [
          "University-Wide",
          "All Colleges"
        ],
        "DE:App 1 Long Name - 1": "Pref Univ",
        "DE:Mailing Components": [
          "Reply Envelope",
          "Outer Envelope",
          "Letter"
        ],
        "DE:App Alloc 1 Code": "ABBRC"
      }
    }
  ]
}

如何使它与新JSON一起使用?

1 个答案:

答案 0 :(得分:1)

由于您的参数名称可以是任何名称,因此建议您在该部分使用Dictionary(Of String, String)。像这样声明模型类:

Class RootObject
    Public Property Data As List(Of Item)
End Class

Class Item
    Public Property ID As String
    Public Property Name As String
    Public Property ObjCode As String
    Public Property ParameterValues As Dictionary(Of String, String)
End Class

使用像Json.Net这样的不错的JSON库,您可以轻松地将JSON反序列化为以下模型:

Dim root As RootObject = JsonConvert.DeserializeObject(Of RootObject)(json)

从那里您可以像使用其他任何类一样使用模型。例如,以下是将所有数据转储到控制台的方法:

For Each item In root.Data
    Console.WriteLine("ID: " & item.ID)
    Console.WriteLine("Name: " & item.Name)
    Console.WriteLine("ObjCode: " & item.ObjCode)
    Console.WriteLine()

    Console.WriteLine(String.Format("{0,-45} {1}", "Parameter Name", "Parameter Value"))
    Console.WriteLine(New String("-", 45) & " " & New String("-", 20))

    For Each kvp In item.ParameterValues
        Console.WriteLine(String.Format("{0,-45} {1}", kvp.Key, kvp.Value))
    Next
Next

正在运行的演示:https://dotnetfiddle.net/SqInI6


要处理您的更新:

看起来您的每个参数值现在都可以是单个字符串或字符串数​​组。这将导致当前代码崩溃,因为字典只能包含简单的字符串值。您可以将字典声明更改为Dictionary(Of String, Object),这将使其反序列化,但是如果这样做,您最终将在字典中混合使用字符串和JArrays。然后,您将需要在所有使用它的地方检查值的类型并适当地处理它,例如:

If kvp.Value Is GetType(JArray) Then
    Dim list As List(Of String) = DirectCast(kvp.Value, JArray).ToObject(Of List(Of String))
    ... handle multiple values ...
Else
    Dim str As String = DirectCast(kvp.Value, String)
    ... handle single value ...
End If

我认为更好的解决方案是将字典更改为Dictionary(Of String, List(Of String)),然后使用自定义JsonConverter从JSON填充字典。这样您就可以在其余的代码中统一处理这些值,因为您知道您将始终拥有一个字符串列表。

如果采用这种方法,则需要以下转换器:

Public Class SingleOrArrayDictionaryConverter(Of T)
    Inherits JsonConverter

    Public Overrides Function CanConvert(objectType As Type) As Boolean
        Return objectType = GetType(Dictionary(Of String, List(Of T)))
    End Function

    Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
        Dim obj = JObject.Load(reader)
        Dim dict = New Dictionary(Of String, List(Of T))
        For Each prop In obj.Properties()
            If prop.Value.Type = JTokenType.Array Then
                dict.Add(prop.Name, prop.Value.ToObject(Of List(Of T)))
            Else
                dict.Add(prop.Name, New List(Of T) From {prop.Value.ToObject(Of T)})
            End If
        Next
        Return dict
    End Function

    Public Overrides ReadOnly Property CanWrite As Boolean
        Get
            Return False
        End Get
    End Property

    Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
        Throw New NotImplementedException()
    End Sub
End Class

要使用转换器,请将<JsonConverter>属性添加到ParameterValues属性中,如下所示:

    <JsonConverter(GetType(SingleOrArrayDictionaryConverter(Of String)))>
    Public Property ParameterValues As Dictionary(Of String, List(Of String))

演示:https://dotnetfiddle.net/oA3bfE