2015-02-08 74 views
4

我对于使用JSON.net并且遇到了一些json有问题,我得到的是有时以数组形式出现并且有时作为单个对象出现的JSON。下面是我用JSON它有如何反序列化可以是数组或单个对象的JSON

一种方式看到的一个例子...

{ 
    "Make": "Dodge", 
    "Model": "Charger", 
    "Lines": [ 
    { 
     "line": "base", 
     "engine": "v6", 
     "color": "red" 
    }, 
    { 
     "line": "R/T", 
     "engine": "v8", 
     "color": "black" 
    } 
    ], 
    "Year": "2013" 
} 

另一种方式是可以派上

{ 
    "Make": "Dodge", 
    "Model": "Charger", 
    "Lines": { 
    "line": "base", 
    "engine": "v6", 
    "color": "red" 
    }, 
    "Year": "2013" 
} 

这里是我一直用于第一种方式工作的代码,并在第二种情况下引发异常。一直在淘金的方式来实现这一点,我真的卡住了。

Public Class jsonCar 
    Public Property make As String 
    Public Property model As String 
    Public Property lines As List(Of jsonCarLines) 
    Public Property year As String 
End Class 

Public Class jsonCarLines 
    Public Property line As String 
    Public Property engine As String 
    Public Property color As String 
End Class 

Module Module1 
    Private Const json As String = "{""Make"":""Dodge"",""Model"":""Charger"",""Lines"": [{""line"":""base"",""engine"": ""v6"",""color"":""red""},{""line"":""R/T"",""engine"":""v8"",""color"":""black""}],""Year"":""2013""}" 
    'Private Const json As String = "{""Make"":""Dodge"",""Model"":""Charger"",""Lines"": {""line"":""R/T"",""engine"":""v8"",""color"":""black""},""Year"":""2013""}" 
    Sub Main() 
     Dim car As jsonCar = JsonConvert.DeserializeObject(Of jsonCar)(json) 

     Console.WriteLine("Make: " & car.make) 
     Console.WriteLine("Model: " & car.model) 
     Console.WriteLine("Year: " & car.year) 
     Console.WriteLine("Lines: ") 
     For Each ln As jsonCarLines In car.lines 
      Console.WriteLine(" Name: " & ln.line) 
      Console.WriteLine(" Engine: " & ln.engine) 
      Console.WriteLine(" Color: " & ln.color) 
      Console.WriteLine() 
     Next 
     Console.ReadLine() 
    End Sub 

End Module 

我猜这可能需要一个自定义的JsonConverter,但我对如何设置它有点不知所措。

+2

我不认为单一的对象可以被写入JSON作为一个对象的数组?这将大大简化事情。事实上,如果允许“行”为一个或多个,这可能是正确的方法。否则,你将不得不编写一个自定义分析器,或者添加必要的'[]'字符的预处理器。为什么允许这种设计? – 2015-02-08 15:30:01

+1

可能的重复[如何使用JSON.net处理同一个属性的单个项目和数组](http://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item -and-an-array-for-the-the-the-property-using-json-n) – 2015-02-08 18:07:56

+0

不幸的是,我没有控制json字符串进来。所以做了字符串操作之后,我被我所得到的东西卡住了。我查看了Brian所引用的问题,并且遇到了问题使其能够正常工作。我认为这里的解决方案感觉更直接,并且在本地VB中,这对我来说是个好处:) – krazifan 2015-02-08 20:56:06

回答

0

你可以做到这一点修改jsonCar类像下面

Public Class jsonCar 
    Public Property make As String 
    Public Property model As String 
    Public Property linesCollection As List(Of jsonCarLines) // Change name 
    Public Property lines As String // Change the type to string 
    Public Property year As String 
End Class 

和代码应该象下面这样:

Dim car As jsonCar = JsonConvert.DeserializeObject(Of jsonCar)(json) 

If (car.lines.StartsWith("[")) Then 
    car.linesCollection = JsonConvert.DeserializeObject(List(Of jsonCarLines))(car.lines) 
Else 
    car.linesCollection = new List(Of jsonCarLines) 
    car.linesCollection.Add(JsonConvert.DeserializeObject(Of jsonCarLines)(car.lines)) 
EndIf 
+0

行绝不是字符串。它可以是数组或对象。因此,如果我将其更改为字符串,那么对于任一版本的json,我都会得到无效的标记异常。 – krazifan 2015-02-08 20:00:53

0

可以一般反序列化对象,然后检查是否有什么。您可以检查JArray或JObject并相应地执行操作。你甚至不需要反序列化成特定的类型,你可以使用Dynamic对象,但这可能不是最好的主意。

Module Module1 

    Sub Main() 
    Dim jsonWithArray As String = "{""Make"":""Dodge"",""Model"":""Charger"",""Lines"": [{""line"":""base"",""engine"": ""v6"",""color"":""red""},{""line"":""R/T"",""engine"":""v8"",""color"":""black""}],""Year"":""2013""}" 
    Dim jsonWithObject As String = "{""Make"":""Dodge"",""Model"":""Charger"",""Lines"": {""line"":""base"",""engine"": ""v6"",""color"":""red""},""Year"":""2013""}" 

    Dim witharray As Newtonsoft.Json.Linq.JObject = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonWithArray) 
    Dim withstring As Newtonsoft.Json.Linq.JObject = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonWithObject) 

    Dim jtokArray As Newtonsoft.Json.Linq.JToken = witharray("Lines") 
    Dim jtokStr As Newtonsoft.Json.Linq.JToken = withstring("Lines") 

    If (jtokArray.GetType() Is GetType(Newtonsoft.Json.Linq.JArray)) Then 
     Console.WriteLine("its an array") 
    End If 

    If (jtokStr.GetType() Is GetType(Newtonsoft.Json.Linq.JObject)) Then 
     Console.WriteLine("its an object") 
    End If 

    Console.ReadKey() 

    End Sub 

End Module 
0

感谢两位冠军编码器& Kundan。我将这两种方法结合起来,并提出了一些适用于两种json输入的方法。这是最终的代码。

Public Class jsonCar 
    Public Property make As String 
    Public Property model As String 
    Public Property linesArray As List(Of jsonCarLines) 
    Public Property year As String 
End Class 

Public Class jsonCarLines 
    Public Property line As String 
    Public Property engine As String 
    Public Property color As String 
End Class 

Module Module1 
    'Private Const json As String = "{""Make"":""Dodge"",""Model"":""Charger"",""Lines"": [{""line"":""base"",""engine"": ""v6"",""color"":""red""},{""line"":""R/T"",""engine"":""v8"",""color"":""black""}],""Year"":""2013""}" 
    Private Const json As String = "{""Make"":""Dodge"",""Model"":""Charger"",""Lines"": {""line"":""R/T"",""engine"":""v8"",""color"":""black""},""Year"":""2013""}" 
    Sub Main() 

     Dim obj As JObject = JsonConvert.DeserializeObject(json) 
     Dim ln As JToken = obj("Lines") 

     Dim car As jsonCar = JsonConvert.DeserializeObject(Of jsonCar)(json) 

     If (ln.GetType() Is GetType(Newtonsoft.Json.Linq.JArray)) Then 
      car.linesArray = JsonConvert.DeserializeObject(Of List(Of jsonCarLines))(JsonConvert.SerializeObject(ln)) 
     End If 

     If (ln.GetType() Is GetType(Newtonsoft.Json.Linq.JObject)) Then 
      car.linesArray = New List(Of jsonCarLines) 
      car.linesArray.Add(JsonConvert.DeserializeObject(Of jsonCarLines)(JsonConvert.SerializeObject(ln))) 
     End If 

     Console.WriteLine("Make: " & car.make) 
     Console.WriteLine("Model: " & car.model) 
     Console.WriteLine("Year: " & car.year) 
     Console.WriteLine("Lines: ") 
     For Each line As jsonCarLines In car.linesArray 
      Console.WriteLine(" Name: " & line.line) 
      Console.WriteLine(" Engine: " & line.engine) 
      Console.WriteLine(" Color: " & line.color) 
      Console.WriteLine() 
     Next 
     Console.ReadLine() 
    End Sub 

End Module 

非常感谢您的快速回复。这解决了我花费大量时间试图弄清楚的问题。

3

这里是如何得到的链接duplicate questionSingleOrArrayConverter解决方案为您的使用情况下工作。

首先,这里是VB翻译的转换器代码。把这个文件保存到项目中的某个类文件中。然后,您可以轻松地将其用于此类任何未来的情况。

Imports Newtonsoft.Json 
Imports Newtonsoft.Json.Linq 

Public Class SingleOrArrayConverter(Of T) 
    Inherits JsonConverter 

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

    Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object 
     Dim token As JToken = JToken.Load(reader) 

     If (token.Type = JTokenType.Array) Then 
      Return token.ToObject(Of List(Of T))() 
     End If 

     Return New List(Of T) From {token.ToObject(Of T)()} 
    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属性,因此它使用SingleOrArrayConverter类。在你的情况下,这看起来像这样:

Public Class jsonCar 
    Public Property make As String 
    Public Property model As String 
    <JsonConverter(GetType(SingleOrArrayConverter(Of jsonCarLines)))> 
    Public Property lines As List(Of jsonCarLines) 
    Public Property year As String 
End Class 

然后,就像你通常会反序列化,它按预期工作。

Dim car As jsonCar = JsonConvert.DeserializeObject(Of jsonCar)(json) 

这里是一个完整的演示:https://dotnetfiddle.net/msYNeQ