json 的键重复问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
katsusan
V2EX    Go 编程语言

json 的键重复问题

  •  
  •   katsusan 2018-11-12 16:17:59 +08:00 6197 次点击
    这是一个创建于 2529 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在写个 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"` 
    第 1 条附言    2018-11-12 17:01:08 +08:00
    28 条回复    2018-11-15 10:39:37 +08:00
    TommyLemon
        1
    TommyLemon  
       2018-11-12 16:25:13 +08:00   1
    这都不是合法的 JSON,解析后就直接最后一个把上面的全覆盖了。
    你把这段 JSON 复制粘贴到这个网站试试,用的是 js 原生的 JSON.parse 解析
    http://apijson.org/
    zjsxwc
        2
    zjsxwc  
       2018-11-12 16:28:23 +08:00
    这个反爬虫 666 !
    zjsxwc
        3
    zjsxwc  
       2018-11-12 16:33:28 +08:00   1
    @zjsxwc

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

    golang 这种碰到就难搞了
    katsusan
        4
    katsusan  
    OP
       2018-11-12 16:37:53 +08:00
    @TommyLemon 是的,确认了的确不符合规范,但不知道 valve 这样做的用意是啥
    TommyLemon
        5
    TommyLemon  
       2018-11-12 16:39:43 +08:00
    @katsusan 估计就不是按照 application/json 格式返回的,可能是 text/plain 这种
    chengfeng1992
        6
    chengfeng1992  
       2018-11-12 16:39:45 +08:00   1
    dota2 ?

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

    比如,trim 后直接把 ``` "abilities": ``` 全 remove 掉,然后用 ``` [] ``` 括起来。
    katsusan
        7
    katsusan  
    OP
       2018-11-12 16:42:21 +08:00
    @zjsxwc 动态语言下的替换指的是正则匹配后替换还是,有思路的话 golang 应该实现也没问题。
    主要是询问有没有碰到过或者见过第三方 json 库支持这种情况的。
    zhujinliang
        8
    zhujinliang  
       2018-11-12 16:44:05 +08:00 via iPhone
    这种用遍历 Token 自己搞吧
    katsusan
        9
    katsusan  
    OP
       2018-11-12 16:45:01 +08:00
    @TommyLemon 是按照 json 返回的,它有个?format=xxx 参数,不指定的话就返回 json,参考网站:
    http://steamwebapi.azurewebsites.net/
    TommyLemon
        10
    TommyLemon  
       2018-11-12 16:45:52 +08:00
    看到上面的链接,随便输入 key 点了下,发现 Response Header 里:
    content-type: text/html
    TommyLemon
        11
    TommyLemon  
       2018-11-12 16:46:49 +08:00
    @katsusan 那就很奇怪了,它的库有问题啊,居然支持在同一层级有同名的 key,或者压根就没用 JSON 库解析过,直接拼出来字符串返回
    zjsxwc
        12
    zjsxwc  
    &nbs;  2018-11-12 16:48:19 +08:00   1
    @katsusan

    字符串替换都可以。

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

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

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

    3. 把剩下的 `"abilities":[` 替换为 `[`
    katsusan
        13
    katsusan  
    OP
       2018-11-12 16:50:36 +08:00
    @TommyLemon key 要去 steam 申请的,随便填应该会返回一个 forbidden 页面,所以是 html 格式,在 chrome 里可以直接看到:
    ```
    Forbidden
    Access is denied. Retrying will not help. Please verify your
    key=
    parameter.
    ```
    ihongren
        14
    ihongren  
       2018-11-12 16:50:48 +08:00
    最外层是个数组吗?
    asLw0P981N0M0TCC
        15
    asLw0P981N0M0TCC  
       2018-11-12 16:52:38 +08:00
    dota2 ! 我记得有个 opendota 和 varendata 的
    katsusan
        16
    katsusan  
    OP
       2018-11-12 17:02:35 +08:00
    @ihongren 是的,以单场比赛为单位,json 附在 append 里了
    katsusan
        17
    katsusan  
    OP
       2018-11-12 17:03:58 +08:00
    @qwertyzzz 是的,应该都是从 apisteam 里取得数据
    O3YwA1ENkb7i35XJ
        18
    O3YwA1ENkb7i35XJ  
       2018-11-12 17:28:20 +08:00
    都不在同一层级, 有啥问题? 哪重复了?
    一个在 "radiant" 节点下, 一个在 "dire" 节点下.

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

    "b": {
    "hello": 456
    }
    }
    ```


    https://imgur.com/a/sLZdgW1
    TommyLemon
        19
    TommyLemon  
       2018-11-12 17:32:56 +08:00
    @katsusan 这个我知道,一般只要 Request 能到达接口,处理后业务错误也应该返回和正确结果格式一致的 Response。
    它既然都提示 key 有问题了,就说明已经经过接口处理过了。
    katsusan
        20
    katsusan  
    OP
       2018-11-12 17:44:43 +08:00
    @xqin 每个 team 下都有 5 个 abilities 键
    ccpp132
        21
    ccpp132  
       2018-11-12 18:27:24 +08:00
    看看你用的 json 库有没有 sax 的接口,这种一般可行
    O3YwA1ENkb7i35XJ
        22
    O3YwA1ENkb7i35XJ  
       2018-11-12 18:46:04 +08:00
    @katsusan 你在 github 上发的那个数据, 并没有你说的这种情况.
    O3YwA1ENkb7i35XJ
        23
    O3YwA1ENkb7i35XJ  
       2018-11-12 18:53:10 +08:00
    @katsusan 不好意思, 看错了, 是我的那个 Chrome 插件解析之后,只剩 4 个了, 查看 原始的数据的时候, 里面是有很多个.
    vishva
        24
    vishva  
       2018-11-12 19:01:13 +08:00
    拿到 json 之后先别解析,将五个"abilities"字符串依次替换成"abilities0","abilities1"...再解析
    mengzhuo
        25
    mengzhuo  
       2018-11-12 19:25:20 +08:00   1
    有个东西叫

    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"`
    }
    gamexg
        26
    gamexg  
       2018-11-12 21:47:48 +08:00   1
    https://github.com/buger/jsonparser

    这种库可以处理这个问题。
    katsusan
        27
    katsusan  
    OP
       2018-11-12 21:53:45 +08:00
    @mengzhuo 谢谢,这个工具不错,但刚才试了这种写法还是只会解析最后一组 abilities 数据。
    reus
        28
    reus  
       2018-11-15 10:39:37 +08:00   1
    这个不难处理,用标准库就行,稍微加点技巧

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

    就是用 json.Decoder.Token 方法把 "abilities" 读掉,然后用 Decode 方法解码后面的数组,直到 Token 返回 '}'
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     951 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 22ms UTC 19:21 PVG 03:21 LAX 12:21 JFK 15:21
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86