如何反序列化混合类型的JSON数组

4
我正在为aigaming.com编写go客户端,当我发出无效请求时,响应将包含一些错误信息。我想使用struct捕获此响应,但是当类型开始混合时,我遇到了麻烦。
错误数据的JSON结构如下:
{  
   "errorMessage":"An error occurred (ValidationException) when calling the Query operation: ExpressionAttributeValues contains invalid value: One or more parameter values were invalid: An AttributeValue may not contain an empty string for key :v0",
   "errorType":"ClientError",
   "stackTrace":[  
      [  
         "/var/task/OfferGame.py",
         612,
         "lambda_handler",
         "game = offerGame.createOffer()"
      ],
      [  
         "/var/task/OfferGame.py",
         586,
         "createOffer",
         "gameRow = self.findSuitableWaitingGame()"
      ],
      [  
         "/var/task/OfferGame.py",
         503,
         "findSuitableWaitingGame",
         "Key('GameStyleId_GameStatus').eq(str(self.gameStyleId) + '_' + self.Game.KEY_GAME_STATUS_WAITING)"
      ]
      // There are more items, but I'll omit them for brevity
   ]
}

这个文本的翻译如下:

捕获大多数信息并不困难,但是stackTrace项会带来麻烦。它是一个混合类型的数组嵌套数组。

到目前为止,我得到的最好结果是使用这个结构体。它实际上没有给我任何数据(所有元素都为空),但它返回了正确数量的元素和嵌套元素。

type ErrorResponse struct {
    ErrorMessage string          `json:"errorMessage"`
    ErrorType    string          `json:"errorType"`
    StackTrace   [][]interface{} `json:"stackTrace"`
}

有没有一种方法可以解析这些混合类型的项目?我是否可以通过将所有整数元素强制转换为字符串来绕过此问题?
更新: 这是我所说的“空”。正确数量的东西都在那里,但它们似乎没有初始化。 {{link1:enter image description here}}

可能是在切片中解组两个不同的结构体的重复问题。 - Peter
它实际上没有给我任何数据(所有元素都为空)”是什么意思?在我看来,你的代码应该没有问题 https://play.golang.org/p/ENGjPf_wZWT。 - mkopriva
@mkopriva 我已经包含了一张截图。感谢您指出那不够清晰。正如您所看到的,正确数量的“东西”都在那里,但它们实际上没有初始化为应该有的数据。 - Niko
@PaulNelsonBaker 对不起,我仍然不清楚缺少什么,请具体说明从 JSON 中缺少哪个数据片段到结构值中? 请在此处查看 https://play.golang.org/p/-R_bC91_ymg - mkopriva
@mkopriva 我现在明白了问题所在。我看了一下调试器,以为我看到了空值。但是你的例子显示:打印值本身显示调试器没有揭示正确的数据,即使它存在。 - Niko
3个回答

3

你走在正确的道路上,只需要继续前进。每当你需要从StackTrace中获取某些东西时,请使用类型断言并根据实际类型执行代码。请注意,类型断言返回2个值,请检查第二个值以确定所假定的类型是否正确。


这实际上是正确的做法。我误解了我所看到的东西。调试器显示空格,我以为这意味着没有加载数据。数据确实存在。现在我们可以对其执行逻辑操作。 - Niko

1

将 StackTrace 的行作为 json.Unmarshaler 实现,并像这样使用:


type ErrorResponse struct {
    ErrorMessage string           `json:"errorMessage"`
    ErrorType    string           `json:"errorType"`
    StackTrace   []StackTraceLine `json:"stackTrace"`
}

type StackTraceLine struct {
    A string
    B int64
    C string
    D string
}

func (l *StackTraceLine) UnmarshalJSON(data []byte) error {
    return json.Unmarshal(data, &[]interface{}{&l.A, &l.B, &l.C, &l.D})
}

func main() {
    var res ErrorResponse
    json.Unmarshal([]byte(`{  
                "errorMessage":"An error occurred (ValidationException) when calling the Query operation: ExpressionAttributeValues contains invalid value: One or more parameter values were invalid: An AttributeValue may not contain an empty string for key :v0",
                "errorType":"ClientError",
                "stackTrace":[  
                    [  
                        "/var/task/OfferGame.py",
                        612,
                        "lambda_handler",
                        "game = offerGame.createOffer()"
                    ],
                    [  
                        "/var/task/OfferGame.py",
                        586,
                        "createOffer",
                        "gameRow = self.findSuitableWaitingGame()"
                    ],
                    [  
                        "/var/task/OfferGame.py",
                        503,
                        "findSuitableWaitingGame",
                        "Key('GameStyleId_GameStatus').eq(str(self.gameStyleId) + '_' + self.Game.KEY_GAME_STATUS_WAITING)"
                    ]
                ]
            }`), &res)
}

playground


0

将 JSON 反序列化为通用的 interface

jsonstr := []byte(`{  
                "errorMessage":"An error occurred (ValidationException) when calling the Query operation: ExpressionAttributeValues contains invalid value: One or more parameter values were invalid: An AttributeValue may not contain an empty string for key :v0",
                "errorType":"ClientError",
                "stackTrace":[  
                    [  
                        "/var/task/OfferGame.py",
                        612,
                        "lambda_handler",
                        "game = offerGame.createOffer()"
                    ],
                    [  
                        "/var/task/OfferGame.py",
                        586,
                        "createOffer",
                        "gameRow = self.findSuitableWaitingGame()"
                    ],
                    [  
                        "/var/task/OfferGame.py",
                        503,
                        "findSuitableWaitingGame",
                        "Key('GameStyleId_GameStatus').eq(str(self.gameStyleId) + '_' + self.Game.KEY_GAME_STATUS_WAITING)"
                    ]
                ]
            }`)

    var dat interface{}
    if err := json.Unmarshal(jsonstr, &dat); err != nil {
        panic(err)
    }

遍历底层的map[string]interface{}

for _, value := range dat.(interface{}).(map[string]interface{}){
    switch tt := value.(type){
    case string:
        fmt.Printf("type is string", tt)
    case float64:
        fmt.Printf("type is float64", tt)
    case bool:
        fmt.Printf("type is boolean", tt)
    case interface{}:
        fmt.Printf("type is interface{}", tt)
    default:
        fmt.Printf("type is unknown", tt)

    }
}

最后,使用switch语句,您可以检查使用类型断言获取的值的类型。

请在Go Playground上检查代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接