解析包含由空行或制表符分隔的多个JSON对象的文件

vbN*_*bie 3 vb.net json json.net

我在尝试正确解析JSON时遇到问题.我有以下格式并尝试使用JObject,但它的作用是将一个对象拆分为不同的对象.也许一个例子是有道理的:

{
  "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"
}
Run Code Online (Sandbox Code Playgroud)

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

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

    Dim results As List(Of JToken) = jobj.Children().ToList
Run Code Online (Sandbox Code Playgroud)

结果包含所有单个令牌.如何将上面的每个对象(整个对象)放入要处理的列表中?

Bri*_*ers 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
Run Code Online (Sandbox Code Playgroud)

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

Dim obj As String = JsonConvert.DeserializeObject(Of RootObject)(json)
Run Code Online (Sandbox Code Playgroud)

因此,此时,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
Run Code Online (Sandbox Code Playgroud)

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

Dim separator As String = vbCrLf + vbCrLf
Dim objects As List(Of RootObject) = ReadJsonFile("json.txt", separator)
Run Code Online (Sandbox Code Playgroud)