更好的方法来反序化Minecraft json

时间:2015-06-27 01:07:00

标签: json vb.net visual-studio-2013 deserialization

我正在尝试使用(1.8.json download)中的 Minecraft json 。样本:

{
  "objects": {
    "realms/lang/de_DE.lang": {
      "hash": "729b2c09d5c588787b23127eeda2730f9c039194",
      "size": 7784
    },
    "realms/lang/cy_GB.lang": {
      "hash": "7b52463b2df4685d2d82c5d257fd5ec79843d618",
      "size": 7688
    },
    "minecraft/sounds/mob/blaze/breathe4.ogg": {
      "hash": "78d544a240d627005aaef6033fd646eafc66fe7a",
      "size": 22054
    },
    "minecraft/sounds/dig/sand4.ogg": {
      "hash": "37afa06f97d58767a1cd1382386db878be1532dd",
      "size": 5491
    }
  }
}

实际的json更长,大约2940行。

我需要一种方法来反序列化这并非完全疯狂 - 使用JSONUtils我得到4411行代码,但相同的代码不能用于任何其他版本的Minecraft。

1 个答案:

答案 0 :(得分:2)

自动化工具非常有用,但它们并不完美 - 特别是在字典方面。

首先要注意的是,所有这些结构都是相同的,即它们都包含hashsize属性。这意味着不是创建数百个相同的类,而是一遍又一遍地使用相同的类:

' the type that repeats from your robot:
Public Class MinecraftItem
    Public Property hash As String
    Public Property size As Int32
End Class

由于自动化工具即时工作(他们不会向前看......或者回来),他们并不是真的知道它们都是一样的。接下来是机器人生成的类在这种情况下不会起作用:

Public Property minecraft/sounds/music/game/creative/creative3.ogg As _
            MinecraftSoundsMusicGameCreativeCreative3Ogg

作为财产名称,这是非法的。但是,名称将作为字典键正常工作。除了上面的MinecraftItem类,我们可能想要一个容器类:

Public Class MinecraftContainer
    Public objects As Dictionary(Of String, MinecraftItem)
End Class

有(至少)3种获取数据的方法:

方法1:拔出单个项目

Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq

Dim jstr As String = ...from whereever

' parse the json into a JObject
Dim js As JObject = JObject.Parse(jstr)

' if you somehow know the names, you can pluck out the data:
Dim mi = js("objects")("minecraft/sounds/mob/blaze/hit2.ogg")

Console.WriteLine(mi("hash").ToString & "    " & mi("size").ToString)

第一行将原始json字符串解析为JObject。这允许我们以各种方式处理内容。例如,我们可以参考"对象"在json和他们的名字项目,这正是在下一行发生的事情:

' drill into "objects", get the "...hit2.ogg" item
Dim mi = js("objects")("minecraft/sounds/mob/blaze/hit2.ogg")

如果您只需要从大文件中获取特定项目,这将有效。创建的mi变量是"特殊" json令牌,所以使用名称来获取你想要的数据位

hash = mi("hash").ToString
size = mi("size").ToString

方法2:反序列化为字典

这将是我的首选方法。包含与第一个示例中相同的Import语句,然后:

' parse the json string
Dim js As JObject = JObject.Parse(jstr)

' deserialize the inner "objects" to a NET Dictionary
Dim myItems = JsonConvert.DeserializeObject(Of Dictionary(Of String, _
                   MinecraftItem))(js("objects").ToString)

这将从json创建myItems作为网络Dictionary(Of String, MincraftItem)。由于MinecraftObject类没有任何但是保留字典,我们跳过它。

键是长名称,每个值都是MinecraftItem,允许您更常规地引用它们:

' get one of the items into a variable
gravel3 = myItems("minecraft/sounds/mob/chicken/step2.ogg")
ConsoleWriteLine("Gravel3  hash: {0},  size: {1}",
                      gravel3.hash, gravel3.size.ToString)

如果您不熟悉.Net Dictionary,它有点像数组或列表,除非您通过Key访问您的项目而不是索引。通过它们循环:

Dim n As Integer = 0
For Each kvp As KeyValuePair(Of String, MinecraftItem) In myItems
    Console.WriteLine("Name: {0}  Hash: {1}  size: {2}",
                      kvp.Key, 
                      kvp.Value.hash, 
                      kvp.Value.size.ToString)
    n += 1
    If n >= 2 Then Exit For           ' just print 3
Next                              

输出:

  

名称:realms / lang / de_DE.lang哈希:10a54fc66c8f479bb65c8d39c3b62265ac82e742尺寸:8112
  名称:realms / lang / cy_GB.lang哈希:14cfb2f24e7d91dbc22a2a0e3b880d9829320243尺寸:7347
  名称:minecraft / sounds / mob / chicken / step2.ogg哈希:bf7fadaf64945f6b31c803d086ac6a652aabef9b尺寸:3838

请记住,密钥始终是长路径名,每个.Value 都是 MinecraftItem对象。

方法3:反序列化为容器

您可以使用MinecraftContainer类跳过解析步骤:

Dim jstr As String = ...from whereever
Dim myJItems = JsonConvert.DeserializeObject(Of MinecraftContainer)(jstr)

请注意,这一次,您将您下载的整个字符串传递给JsonConvert。结果将是一个额外的外部对象,其中包含一个名为" Objects"的字典属性。因此,您使用一些主要参考文献引用项目:

gravel3hash = myJItems.Object("minecraft/sounds/dig/gravel3.ogg").hash

gravel3 = myJItems.Object("minecraft/sounds/dig/gravel3.ogg")
    ConsoleWriteLine("Gravel3  hash: {0},  size: {1}",
                      gravel3.hash, gravel3.size.ToString)
'or:
ConsoleWriteLine("Gravel3  hash: {0},  size: {1}",
                   myJItems.Object("minecraft/sounds/dig/gravel3.ogg").hash, 
                   myJItems.Object("minecraft/sounds/dig/gravel3.ogg").size.ToString)   

这种方法只是反序列化的一行代码,但它意味着   a)我必须定义容器类和
  b)我必须使用myJItems.Object钻入其他空容器以获取字典。

就个人而言,我会放弃这个并使用方法2 - 一行额外的代码使得它更容易使用。也就是说,您还可以从容器中提取字典集合:

Dim myItems As Dictionary(Of String, MinecraftItem)= myJItems.Object