2015-02-08 70 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

相關問題