我正在尝试从(1.8.json下载)使用 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。
自动化工具可能非常有用,但并不完美-尤其是在字典方面。
首先要注意的是,它们的结构都是相同的,即它们都由hash和size属性组成。这意味着我们可以一遍又一遍地使用相同的类,而不是创建数百个相同的类:
hash
size
' 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
作为属性名称,这是非法的。但是,这些名称可以用作Dictionary键。除了上述MinecraftItem类之外,我们 可能还 需要一个容器类:
MinecraftItem
Public Class MinecraftContainer Public objects As Dictionary(Of String, MinecraftItem) End Class
至少有3种获取数据的方法:
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令牌,因此请使用名称来获取所需的数据位
mi
hash = mi("hash").ToString size = mi("size").ToString
这将是 我的 首选方法。包括与Import第一个示例相同的语句,然后:
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为Net Dictionary(Of String, MincraftItem)。由于MinecraftObject该类除了保留字典外 什么 也不做,因此我们跳过了它。
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字典,则它有点像数组或列表,只是您通过一个Key而不是索引来访问项目。要遍历它们:
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
输出:
名称:三界/郎/ de_DE.lang哈希:10a54fc66c8f479bb65c8d39c3b62265ac82e742尺寸:8112 姓名:三界/郎/ cy_GB.lang哈希:14cfb2f24e7d91dbc22a2a0e3b880d9829320243尺寸:7347 姓名:我的世界/声音/暴民/鸡肉/ step2.ogg哈希:bf7fadaf64945f6b31c803d086ac6a652aabef9b尺寸:3838
请记住,Key始终是长路径名,每个.Value 都是 MinecraftItem对象。
.Value
您可以使用以下MinecraftContainer类跳过分析步骤:
MinecraftContainer
Dim jstr As String = ...from whereever Dim myJItems = JsonConvert.DeserializeObject(Of MinecraftContainer)(jstr)
请注意,这次,您将 下载的整个字符串 传递给JsonConvert。结果将是一个额外的外部对象,其中包含一个名为“ Objects”的字典属性。因此,您使用一些主要参考文献来引用这些项目:
JsonConvert
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钻入否则为空的容器才能获得Dictionary。
myJItems.Object
就个人而言,我会放弃使用方法2-额外增加一行代码,使其更易于使用。也就是说,您还可以从容器中提取字典集合:
Dim myItems As Dictionary(Of String, MinecraftItem)= myJItems.Object