反序列化 Minecraft json 的更好方法 [英] Better way to deserialize Minecraft json

查看:27
本文介绍了反序列化 Minecraft json 的更好方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用来自 (Minecraft json>1.8.json 下载).示例:

I am trying to work with Minecraft json from (1.8.json download). A Sample:

{
  "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 行.

The actual json is much longer, some 2940 lines.

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

I need a way to deserialize this that isn't completely insane - using JSONUtils I get 4411 Lines of Code, but the same code can't be used for any other version of Minecraft.

推荐答案

自动化工具可能非常有用,但它们并不完美 - 特别是在涉及词典时.

The automated tools can be very useful, but they are not perfect - especially when it comes to dictionaries.

首先要注意的是,它们的结构都是相同的,即它们都由 hashsize 属性组成.这意味着我们可以一遍又一遍地使用同一个类,而不是创建数百个相同的类:

The first thing to note is that the structure is the same for all of them, that is they all consist of hash and size properties. This means rather than creating hundreds of identical classes we can use the same one over and over:

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

由于自动化工具正在运行(它们不会向前看……或向后看),因此它们并不真正知道它们都是一样的.接下来是机器人生成的类在这种情况下不起作用:

Since the automated tools are working on the fly (they do not look ahead...or back) they don't really know that they are all the same. The next thing is that the classes the robots generate wont work in this case:

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

这作为属性名称是非法的.但是,名称可以作为字典键正常工作.除了上面的 MinecraftItem 类,我们可能还需要一个容器类:

That is illegal as a property name. However, the names will work just fine as Dictionary keys. In addition to the above MinecraftItem class, we might want a container class:

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

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

There are (at least) 3 ways to get at the data:

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 中引用对象",并按名称引用它们,这正是下一行中发生的事情:

The first line parses the original json string into a JObject. This allows us to work with the contents in various ways. For instance, we can reference "objects" in the json and them the items by name, which is exactly what happens in the next line:

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

如果您只需要从大文件中获取特定项目,这将起作用.创建的 mi 变量是一个特殊"的 json 标记,因此使用名称来获取您想要的数据位

This will work if you just need to fetch a particular item from the big file. The mi variable created is a "special" json token, so use the names to get the data bits you want

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

方法二:反序列化成字典

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

Method 2: Deserialize To a Dictionary

This would be my preferred method. Include the same Import statements as in the first example, then:

' 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)

这将创建 myItems 作为来自 json 的 Net Dictionary(Of String, MincraftItem).由于 MinecraftObject 类除了保存字典之外不做任何任何事情,我们跳过了它.

This will create myItems as a Net Dictionary(Of String, MincraftItem) from the json. Since the MinecraftObject class doesn't do anything but hold the dictionary, we skipped it.

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

The keys are the long names and each value is a MinecraftItem which allows you to reference them more conventionally:

' 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字典 它有点像数组或列表,除了您通过 Key 而不是索引访问您的项目.遍历它们:

If you are not familiar with the .Net Dictionary it is somewhat like an array or List except you access your items by a Key rather then index. To loop thru them all:

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

Name: realms/lang/de_DE.lang Hash: 10a54fc66c8f479bb65c8d39c3b62265ac82e742 size: 8112
Name: realms/lang/cy_GB.lang Hash: 14cfb2f24e7d91dbc22a2a0e3b880d9829320243 size: 7347
Name: minecraft/sounds/mob/chicken/step2.ogg Hash: bf7fadaf64945f6b31c803d086ac6a652aabef9b size: 3838

请记住,Key 将始终是长路径名,并且每个 .Value is MinecraftItem 对象.

Just remember, the Key will always be the long path name, and each .Value is MinecraftItem object.

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

You can skip the parsing step by using the MinecraftContainer class:

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

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

Note that this time, you pass the entire string you downloaded to JsonConvert. The result will be an extra outer object which contains a dictionary property named "Objects". So, you reference the items using some leading references:

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 来钻取原本为空的容器以获取字典.

This method is just one line of code to deserialize, but it means
a) I have to define the container class and
b) I have to use myJItems.Object to drill into the otherwise empty container to get at the Dictionary.

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

Personally, I would forego this and use method 2 - one extra line of code makes it a bit easier to work with. That said, you can also extract the dictionary collection from the container:

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

这篇关于反序列化 Minecraft json 的更好方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆