【问题标题】:Set property of a nested JSON object设置嵌套 JSON 对象的属性
【发布时间】:2020-11-06 21:03:56
【问题描述】:

我是 JSON.Net 的新手,无法弄清楚如何将我的 JSON 的嵌套对象作为JObject 获取。我正在使用一个文件来存储我的 JSON 对象,然后将我所做的更改写回该文件。

背景

我正在尝试制作一个应用程序,用户在其计算机上选择一个文件夹,该应用程序将该文件夹及其所有文件枚举到 JSON 对象中。然后,用户可以选择这些文件中的任何一个并设置该文件的值以保存到 JSON 文件中。到目前为止,我已经完成了将目录结构/包含的文件生成为 JSON 并将其保存到文件中的功能,但我一直在尝试访问 JSON 的嵌套对象以设置属性值。

到目前为止我的代码

用于生成 JSON 并将其存储到文件中的代码是:

Private Sub btnAddFolder_Click(sender As Object, e As EventArgs) Handles btnAddFolder.Click

    'Create JObject from JSON File
    Dim json = File.ReadAllText(jsonFile)
    Dim obj As New JObject
    If json <> "" Then
        obj = JObject.Parse(json)
    End If

    'Add directory as a nested object of JSON
    ' - Add all of files in directory as nested objects of the directory object
    If obj.Property(txtDirectory.Text) Is Nothing Then
        'Object to store all files as nested objects
        Dim files As New JObject
        'Object to store all properties of a file object
        Dim fileInfo As New JObject
        'Variables to store properties for fileInfo
        Dim stringProp As String = "default"
        Dim arrProp() As String = {"default"}
        Dim jArrProp As JArray = JArray.FromObject(arrProp)

        'Add properties to objcet
        fileInfo.Add("var1", stringProp)
        fileInfo.Add("var2", jArrProp)

        'Add object of properties to each file object
        For Each file As String In Directory.GetFiles(txtDirectory.Text)
            files.Add(file, fileInfo)
        Next

        'Add each file object to directory object
        obj.Add(txtDirectory.Text, files)
    End If

    'Write JSON to file
    File.WriteAllText(jsonFile, JsonConvert.SerializeObject(obj, 1))
End Sub

生成的文件/JSON 看起来像:

{
  "Directory1": {
    "File1": {
      "var1": "default",
      "var2": ["default"]
    },
    "File2": {
      "var1": "default",
      "var2": ["default"]
    }
  },
  "Directory2": {
    "File1": {
      "var1": "default",
      "var2": ["default"]
    },
    "File2": {
      "var1": "default",
      "var2": ["default"]
    }
  }
}

接下来我需要什么

当单击标记为Add Folder 的按钮时调用上面的代码。
另一个标记为Select File and Set Data 的按钮提示用户从目录中选择任何文件并输入将存储在该文件的var1 和var2 中的值。

例如,当单击Select File and Set Data 按钮时,用户选择File1,然后写下“此文件是我 2012 年去岛屿度假的照片”。在一个文本框中。我需要我的代码将obj.Directory1.File1 的var1 设置为指定的字符串值。
这就是我难住的地方。我不知道如何使用 JSON.net 访问嵌套对象以设置其属性之一的值。

我知道 JObject 有一个 .Property().Value() 方法,可用于设置或获取属性的值,但由于我的预期 JSON 对象嵌套在主 JSON 对象中,我不知道如何将其作为JObject 获取以访问该方法。 JObject.Item() 返回一个没有 .Property().Value() 方法的 JToken。

【问题讨论】:

    标签: json vb.net winforms json.net


    【解决方案1】:

    您的 JSON 结构包含目录名称或完整路径,它们都是不同的,因此类模型对于描述此 JSON 的全部内容并不是很有用。
    由于目录路径是唯一的(不能有两个相同的路径指向不同的目录根),因此目录路径可以用作字典的键。
    使用 Dictionary.ContainsKey("Key") 方法确定 Dictionary 是否已经包含该键也很简单(因为您正在代码中检查它)。

    这同样适用于文件名:通常目录不能包含具有相同名称的文件。因此,您可以使用文件路径作为第二个字典的键,它是第一个字典的值(如上所述,将目录作为键)。

    var1 和 var2 值始终相同,因此您可以使用类模型来描述此结构。您还可以为属性分配默认值(以不同的方式;这里我只是明确地分配默认值)

    Public Class FileObj
        <JsonProperty("var1")>
        Public Property Var1 As String = "default"
        <JsonProperty("var2")>
        Public Property Var2 As List(Of String) = New List(Of String)({"default"})
    End Class
    

    此时,当您对 JSON 进行反序列化后,您只需检查 Dictionary 是否已经包含与新目录路径相等的 Key。
    如果没有,则添加此新键和 Dictionary(Of String, FileObj) 作为值,其中 Key 是文件名,FileObj 是包含您的两个属性的类:

    加载已经保存的内容,如果有的话:

    Private DirectoryObjects As Dictionary(Of String, Dictionary(Of String, FileObj))
    
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim json = File.ReadAllText(jsonFile)
        DirectoryObjects = JsonConvert.DeserializeObject(
            Of Dictionary(Of String, Dictionary(Of String, FileObj)))(json)
    End Sub
    

    在当前字典中添加一个新的目录结构:

    Private Sub btnAddFolder_Click(sender As Object, e As EventArgs) Handles btnAddFolder.Click
        Dim dirPath = txtDirectory.Text
        If DirectoryObjects.ContainsKey(dirPath) Then Return
    
        Dim fileInfo As New Dictionary(Of String, FileObj)()
        For Each file As String In Directory.GetFiles(dirPath)
            fileInfo.Add(file, New FileObj() With {
                .Var1 = "Something",
                .Var2 = New List(Of String)({"Something", "Else"})
            })
        Next
    
        DirectoryObjects.Add(dirPath, fileInfo)
    
        ' Now you can serialize and write to disc to preserve the changes
        Dim dirInfoJson = JsonConvert.SerializeObject(DirectoryObjects)
        File.WriteAllText(jsonFile, dirInfoJson)
    End Sub
    

    现在,您可以使用 ComboBox - 选择其中一个目录 - 和 ListBox / ListView - 显示所选目录的内容。
    选择一个文件时,目录是外部字典的键,文件内部字典的键。

    ► Dictionary.ToList() 可以用作大多数保存项目集合的控件的数据源。

    • txtDescription.Text 表示与var1 相关的用户输入
    • txtDataVar2a.Text 和 txtDataVar2b.Text 表示 var2 值的其他输入。
    Private Sub btnEditFileInfo_Click(sender As Object, e As EventArgs) Handles btnEditFileInfo.Click
        ' Get the inner Dictionary using the Directory as the Key of the outer Dictionary
        Dim fileObjects As Dictionary(Of String, FileObj) = DirectoryObjects(txtDirectory.Text)
        ' Get the FileObj object using the File as the Key of the inner Dictionary
        Dim fileInfo As FileObj = fileObjects("[Selected File Path]")
        ' Add the new Values to var1 and var2
        fileInfo.Var1 = txtDescription.Text
        fileInfo.Var2 = New List(Of String)({txtDataVar2a.Text, txtDataVar2b.Text})
    
        ' You can serialize the Dictionary now or do it later
        Dim dirInfoJson = JsonConvert.SerializeObject(DirectoryObjects)
        File.WriteAllText(jsonFile, dirInfoJson)
    End Sub
    

    您会看到此 JSON 结构与您在此处显示的结构相同。

    注意:
    新文件系统中的文件名有可能区分大小写,但这不是问题,因为我们的字符串比较也是区分大小写的。

    【讨论】:

    • 这是一个完美的解决方案,Jimi,非常感谢您为此付出的时间和精力。对于发现此问题的其他任何人:我的问题的通用答案是:创建一个模仿 JSON 属性的类,然后创建一个嵌套的 Dictionary,其嵌套与您的 JSON 一样多,Dictionary 中的最后一个条目作为您的类类型。然后,对 Dict 对象进行更改并将其序列化回 JSON 文件。值得注意的是,如果您的 .json 文件完全为空,则代码将失败。您的“空白”文件应该是“{}”,因此代码会生成一个空对象而不是没有对象。
    猜你喜欢
    • 1970-01-01
    • 2013-09-27
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-16
    相关资源
    最近更新 更多