Golang Go语言中json的键重复问题

发布于 1周前 作者 vueper 来自 Go语言

Golang Go语言中json的键重复问题

最近在写个 steam 的第三方 api,其中有个接口是返回当前联赛中的比赛详细资料。url 是下面这个:

https://api.steampowered.com/IDOTA2Match_570/GetLiveLeagueGames/v1?key=<apikey>

但它返回的 json 里英雄描述技能升级的 key 是重复的,这个应该是不符合 json 编码标准的吧(没想到浓眉大眼的沃尔沃也干了),例如下:

"abilities":[  // <-这样的"abilities"键总共有 5 个(代表 5 个英雄的技能升级情况)
{
"ability_id":5106,   //唯一技能 ID
"ability_level":2  //技能等级
},
{
"ability_id":5107,
"ability_level":3
}
]
,
"abilities":[
{
"ability_id":5082,
"ability_level":3
},
{
"ability_id":5083,
"ability_level":2
}
]
,
"abilities":[
{
"ability_id":5122,
"ability_level":3
},
{
"ability_id":5123,
"ability_level":2
},
{
"ability_id":5125,
"ability_level":1
}
]

我尝试在结构体里用相同的 json tag 指定不同的字段但自带的 json 包好像解析不出来,求知道的大佬指点下。

	Abilities1 []struct {
		AbilityID    uint16 `json:"ability_id"`
		AbilityLevel uint8  `json:"ability_level"`
	} `json:"abilities"`
	Abilities2 []struct {
		AbilityID    uint16 `json:"ability_id"`
		AbilityLevel uint8  `json:"ability_level"`
	} `json:"abilities"`

更多关于Golang Go语言中json的键重复问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

29 回复

这都不是合法的 JSON,解析后就直接最后一个把上面的全覆盖了。
你把这段 JSON 复制粘贴到这个网站试试,用的是 js 原生的 JSON.parse 解析
http://apijson.org/

更多关于Golang Go语言中json的键重复问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这个反爬虫 666 !



如果是动态语言,简单字符串替换下把abilities替换为 abilities__&lt;index_num&gt;然后就可以处理了,

golang 这种碰到就难搞了

是的,确认了的确不符合规范,但不知道 valve 这样做的用意是啥

估计就不是按照 application/json 格式返回的,可能是 text/plain 这种

dota2 ?

这个是不是考虑自己先把 json 字符串特殊处理一下呢?

比如,trim 后直接把 "abilities": 全 remove 掉,然后用 [] 括起来。

动态语言下的替换指的是正则匹配后替换还是,有思路的话 golang 应该实现也没问题。
主要是询问有没有碰到过或者见过第三方 json 库支持这种情况的。

这种用遍历 Token 自己搞吧

是按照 json 返回的,它有个?format=xxx 参数,不指定的话就返回 json,参考网站:
http://steamwebapi.azurewebsites.net/

看到上面的链接,随便输入 key 点了下,发现 Response Header 里:
content-type: text/html

那就很奇怪了,它的库有问题啊,居然支持在同一层级有同名的 key,或者压根就没用 JSON 库解析过,直接拼出来字符串返回



字符串替换都可以。

golang 你也手动替换成合法的 json 吧,

1. 把第一个"abilities":[ 替换为 "abilities":[[

2. 把最后一个"ability_level":1}] 替换为 "ability_level":1}]]

3. 把剩下的 "abilities":[ 替换为 [

key 要去 steam 申请的,随便填应该会返回一个 forbidden 页面,所以是 html 格式,在 chrome 里可以直接看到:
<br>Forbidden<br>Access is denied. Retrying will not help. Please verify your<br>key=<br>parameter.<br>

最外层是个数组吗?

dota2 ! 我记得有个 opendota 和 varendata 的

是的,以单场比赛为单位,json 附在 append 里了

是的,应该都是从 apisteam 里取得数据

都不在同一层级, 有啥问题? 哪重复了?
一个在 “radiant” 节点下, 一个在 “dire” 节点下.

类似于下面这样, 你能说下面的 hello 是重复键?
<br>{<br>"a": {<br> "hello": 123<br>},<br><br>"b": {<br> "hello": 456<br>}<br>}<br>


https://imgur.com/a/sLZdgW1

这个我知道,一般只要 Request 能到达接口,处理后业务错误也应该返回和正确结果格式一致的 Response。
它既然都提示 key 有问题了,就说明已经经过接口处理过了。

每个 team 下都有 5 个 abilities 键

看看你用的 json 库有没有 sax 的接口,这种一般可行

你在 github 上发的那个数据, 并没有你说的这种情况.

不好意思, 看错了, 是我的那个 Chrome 插件解析之后,只剩 4 个了, 查看 原始的数据的时候, 里面是有很多个.

拿到 json 之后先别解析,将五个"abilities"字符串依次替换成"abilities0",“abilities1”…再解析

有个东西叫

json-to-go
https://mholt.github.io/json-to-go/

type AutoGenerated struct {
Abilities []struct {
AbilityID int json:"ability_id"
AbilityLevel int json:"ability_level"
} json:"abilities"
}

谢谢,这个工具不错,但刚才试了这种写法还是只会解析最后一组 abilities 数据。

这个不难处理,用标准库就行,稍微加点技巧

https://gist.github.com/reusee/2cf9de7bbf46e6049a798630002db54b

就是用 json.Decoder.Token 方法把 “abilities” 读掉,然后用 Decode 方法解码后面的数组,直到 Token 返回 ‘}’

在Golang(Go语言)中处理JSON数据时,遇到键重复的问题是比较少见的,因为标准的JSON格式规范要求键是唯一的。然而,如果你确实遇到或需要处理含有重复键的非标准JSON数据,这里有一些处理方式:

  1. 解析为map[string]interface{}: Go的encoding/json包在解析JSON到map[string]interface{}时,如果遇到重复键,后面的值会覆盖前面的值。这意味着最终map中只保留最后一个键对应的值。

  2. 使用自定义解析器: 如果你需要保留所有重复键的值(例如,存储为数组或切片),你可以实现一个自定义的UnmarshalJSON方法。这通常涉及到先将JSON解析为原始的字节数组或[]byte,然后手动解析这些字节来捕获所有键和值。

  3. 使用第三方库: 有些第三方库可能提供了更灵活的处理重复键的方法。这些库可能允许你定义自定义的解析行为,比如将重复键的值收集到切片中。

  4. 预处理JSON: 如果可能,最好在JSON数据到达你的应用之前就解决键重复的问题。这可以通过修改生成JSON数据的源头或使用一个中间步骤来预处理JSON数据。

总之,标准的Go JSON处理库不支持直接处理重复键的情况,但你可以通过自定义解析逻辑或使用第三方库来实现这一需求。在大多数情况下,确保JSON数据的键是唯一的,是避免此类问题的最佳实践。

回到顶部