3

我无法在这里正确解析 JSON。我有以下格式并尝试使用 JObjects,但它所做的是将一个对象拆分为不同的对象。也许一个例子会很有意义:

{
  "completed_in": 0.012,
  "max_id": 136536013832069120,
  "max_id_str": "136536013832069120",
  "next_page": "?page=2&max_id=136536013832069120&q=twitterapi&rpp=1",
  "page": 1,
  "query": "twitterapi",
  "refresh_url": "?since_id=136536013832069120&q=twitterapi",
  "results": [
  {
  "created_at": "Tue, 15 Nov 2011 20:08:17 +0000",
  "from_user": "fakekurrik",
  "from_user_id": 370773112,
  "from_user_id_str": "370773112",
  "from_user_name": "fakekurrik",
  "geo": null,
  "id": 136536013832069120,
  "id_str": "136536013832069120",
  "iso_language_code": "en",
  "metadata": {
    "result_type": "recent"
  },
  "profile_image_url": "http://a1.twimg.com/profile_images/1540298033/phatkicks_normal.jpg",
  "source": "<a href="http://twitter.com/">web</a>",
  "text": "@twitterapi, keep on keeping it real",
  "to_user": "twitterapi",
  "to_user_id": 6253282,
  "to_user_id_str": "6253282",
  "to_user_name": "Twitter API"
  }
],
"results_per_page": 1,
 "since_id": 0,
 "since_id_str": "0"
}

这是我认为的一个对象。我的文件有数百个,只是用制表符或空行分隔。现在如果我使用 JObject

   Dim jobj As JObject = JObject.Parse(txtStuff.ToString())

    Dim results As List(Of JToken) = jobj.Children().ToList

结果包含所有单独的标记。如何将上述每个对象(整个对象)放入要处理的列表中?

4

1 回答 1

5

听起来你真的在这里问了两个问题。

  1. 鉴于上述 JSON,我如何将数据放入一个好的对象结构中?
  2. 鉴于我有包含大量这些对象的文件,我如何将它们放入列表中?

第一部分非常简单。只需定义一个与您的 JSON 匹配的类结构,然后用于JsonConvert.DeserializeObject()将 JSON 反序列化为该对象。对于您发布的 JSON,类结构如下所示:

Class RootObject
    Public Property completed_in As Double
    Public Property max_id As Long
    Public Property max_id_str As String
    Public Property next_page As String
    Public Property page As Integer
    Public Property query As String
    Public Property refresh_url As String
    Public Property results As List(Of Result)
    Public Property results_per_page As Integer
    Public Property since_id As Integer
    Public Property since_id_str As String
End Class

Class Result
    Public Property created_at As String
    Public Property from_user As String
    Public Property from_user_id As Integer
    Public Property from_user_id_str As String
    Public Property from_user_name As String
    Public Property geo As Object
    Public Property id As Long
    Public Property id_str As String
    Public Property iso_language_code As String
    Public Property metadata As Metadata
    Public Property profile_image_url As String
    Public Property source As String
    Public Property text As String
    Public Property to_user As String
    Public Property to_user_id As Integer
    Public Property to_user_id_str As String
    Public Property to_user_name As String
End Class

Class Metadata
    Public Property result_type As String
End Class

你可以像这样反序列化它:

Dim obj As String = JsonConvert.DeserializeObject(Of RootObject)(json)

因此,此时,obj将包含您在问题中定义的一个对象的所有数据。现在,您已经表明您有一个文件,其中包含许多这些 JSON 对象,这些对象由制表符或空行分隔。您不能只读取整个文件并将其作为一个大字符串提供给 JSON 解析器,因为这种格式不是有效的 JSON。(当然,每个单独的对象都是有效的 JSON,但是当与制表符或空行分隔符串在一起时,整体无效。)因此,您需要逐行(或可能逐个字符)读取文件以找到分隔符并将其分解为解析器可以解析的有效 JSON 对象理解。每次找到分隔符时,将自上次分隔符后读取的所有数据都提供给反序列化器。每次反序列化的结果都是有效的RootObject,然后您可以将其添加到列表中。

这里有一些代码可以让你了解它是如何工作的。您可能需要根据自己的需要对其进行调整,但我猜它并没有那么离谱。

'' This function will read a file containing a series of JSON objects separated by 
'' some string that is NOT part of the JSON.  Could be a blank line or a tab or 
'' something else.  It will return a list of the deserialized JSON objects.
'' This function relies on two other helper functions (below).
Function ReadJsonFile(fileName As String, separator As String) As List(Of RootObject)
    Dim objects As New List(Of RootObject)
    Using sr As New StreamReader(fileName)
        Dim json As String
        Do
            json = ReadToSeparator(sr, separator)
            If json.Length > 0 Then
                objects.Add(JsonConvert.DeserializeObject(Of RootObject)(json))
            End If
        Loop Until json.Length = 0
    End Using
    Return objects
End Function

'' This function will read and build up a string until the given separator is found.
'' Once the separator is found, it returns the string with the separator removed.
'' If no separator is found before the end of the data is reached, it returns
'' whatever was read to that point.
Function ReadToSeparator(reader As TextReader, separator As String) As String
    Dim sb As New StringBuilder()
    While reader.Peek <> -1
        Dim ch As Char = ChrW(reader.Read())
        sb.Append(ch)
        If TailMatchesSeparator(sb, separator) Then
            sb.Remove(sb.Length - separator.Length, separator.Length)
            Exit While
        End If
    End While
    Return sb.ToString()
End Function

'' This function checks whether the last characters in a StringBuffer match the
'' given separator string.  Returns true if so or false if not.
Function TailMatchesSeparator(sb As StringBuilder, separator As String) As Boolean
    If sb.Length >= separator.Length Then
        Dim i As Integer = sb.Length - 1
        For j As Integer = separator.Length - 1 To 0 Step -1
            If sb(i) <> separator(j) Then
                Return False
            End If
            i = i - 1
        Next
        Return True
    End If
    Return False
End Function

要使用它,只需调用ReadJsonFile,传递文件名和分隔符字符串。例如:

Dim separator As String = vbCrLf + vbCrLf
Dim objects As List(Of RootObject) = ReadJsonFile("json.txt", separator)
于 2013-10-22T07:40:00.553 回答