如何解决您如何在Golang中修改此结构以接受两个不同的结果?
对于以下JSON响应{"table_contents":[{"id":100,"description":"text100"},{"id":101,"description":"text101"},{"id":1,"description":"text1"}]}
您要做的就是产生以下代码以正确执行它,并能够从该结构读取字段,例如:
package main
import (
"fmt"
"encoding/json"
)
type MyStruct1 struct {
TableContents []struct {
ID int
Description string
} `json:"table_contents"`
}
func main() {
result:= []byte(`{"table_contents":[{"id":100,"description":"text1"}]}`)
var container MyStruct1
err := json.Unmarshal(result,&container)
if err != nil {
fmt.Println(" [0] Error message: " + err.Error())
return
}
for i := range container.TableContents {
fmt.Println(container.TableContents[i].Description)
}
}
但是您如何处理以下JSON响应? {"table_contents":[[{"id":100,"description":"text101"}],"description":"text1"}]}
既可以得到此响应,也可以得到上面的响应,修改结构以使其同时接受这很重要。
在互联网的帮助下,我做了这样的事情:
package main
import (
"fmt"
"encoding/json"
)
type MyStruct1 struct {
TableContents []TableContentUnion `json:"table_contents"`
}
type TableContentClass struct {
ID int
Description string
}
type TableContentUnion struct {
TableContentClass *TableContentClass
TableContentClassArray []TableContentClass
}
func main() {
result:= []byte(`{"table_contents":[[{"id":100,&container)
if err != nil {
fmt.Println(" [0] Error message: " + err.Error())
return
}
for i := range container.TableContents {
fmt.Println(container.TableContents[i])
}
}
但它不会超过错误消息:(
- [0]错误消息:json:无法将数组解组为main.TableContentUnion *类型的Go struct字段MyStruct1.table_contents
数小时以来一直在努力提出解决方案。如果有人可以帮我,我会很高兴。感谢您的阅读。让我知道你是否有疑问
解决方法
在table_contents
内部,您有两个类型选项(json对象或json对象列表)。您可以做的是解组到接口,然后在使用接口时对其进行类型检查:
type MyStruct1 struct {
TableContents []interface{} `json:"table_contents"`
}
...
for i := range container.TableContents {
switch container.TableContents[i].(type){
case map[string]interface{}:
fmt.Println("json object")
case []interface{}:
fmt.Println("list")
}
}
从那里,您可以使用一些库(例如https://github.com/mitchellh/mapstructure)将未编组的结构映射到您的TableContentClass
类型。在此处查看PoC游乐场:https://play.golang.org/p/NhVUhQayeL_C
自定义UnmarshalJSON
函数
您还可以在具有两种可能性的对象上创建自定义UnmarshalJSON函数。如果您是TableContentUnion
。
然后在自定义解组器中决定如何解组内容。
func (s *TableContentUnion) UnmarshalJSON(b []byte) error {
// Note that we get `b` as bytes,so we can also manually check to see
// if it is an array (starts with `[`) or an object (starts with `{`)
var jsonObj interface{}
if err := json.Unmarshal(b,&jsonObj); err != nil {
return err
}
switch jsonObj.(type) {
case map[string]interface{}:
// Note: instead of using json.Unmarshal again,we could also cast the interface
// and build the values as in the example above
var tableContentClass TableContentClass
if err := json.Unmarshal(b,&tableContentClass); err != nil {
return err
}
s.TableContentClass = &tableContentClass
case []interface{}:
// Note: instead of using json.Unmarshal again,we could also cast the interface
// and build the values as in the example above
if err := json.Unmarshal(b,&s.TableContentClassArray); err != nil {
return err
}
default:
return errors.New("TableContentUnion.UnmarshalJSON: unknown content type")
}
return nil
}
然后其余的工作就像在之前失败的测试代码中一样。这里工作的Go Playground
解组到map
并手动构建struct
您始终可以将json(具有对象的根)解组到map[string]interface{}
中。然后,您可以对事物进行迭代,并在检查它们的类型之后进一步解组它们。
工作示例:
func main() {
result := []byte(`{"table_contents":[[{"id":100,"description":"text100"},{"id":101,"description":"text101"}],{"id":1,"description":"text1"}]}`)
var jsonMap map[string]interface{}
err := json.Unmarshal(result,&jsonMap)
if err != nil {
fmt.Println(" [0] Error message: " + err.Error())
return
}
cts,ok := jsonMap["table_contents"].([]interface{})
if !ok {
// Note: nil or missing 'table_contents" will also lead to this path.
fmt.Println("table_contents is not a slice")
return
}
var unions []TableContentUnion
for _,content := range cts {
var union TableContentUnion
if contents,ok := content.([]interface{}); ok {
for _,content := range contents {
contCls := parseContentClass(content)
if contCls == nil {
continue
}
union.TableContentClassArray = append(union.TableContentClassArray,*contCls)
}
} else {
contCls := parseContentClass(content)
union.TableContentClass = contCls
}
unions = append(unions,union)
}
container := MyStruct1{
TableContents: unions,}
for i := range container.TableContents {
fmt.Println(container.TableContents[i])
}
}
func parseContentClass(value interface{}) *TableContentClass {
m,ok := value.(map[string]interface{})
if !ok {
return nil
}
return &TableContentClass{
ID: int(m["id"].(float64)),Description: m["description"].(string),}
}
如果json的变化太多,这将非常有用。对于这种情况,有时切换到工作方式类似于https://github.com/tidwall/gjson的json包可能也很有意义,该json包根据其路径获取值。
,使用json.RawMessage捕获JSON文档的各个部分。视情况解封每个原始消息。
-> std::pair<double,char>&
像这样使用它:
func (ms *MyStruct1) UnmarshalJSON(data []byte) error {
// Declare new type with same base type as MyStruct1.
// This breaks recursion in call to json.Unmarshal below.
type x MyStruct1
v := struct {
*x
// Override TableContents field with raw message.
TableContents []json.RawMessage `json:"table_contents"`
}{
// Unmarshal all but TableContents directly to the
// receiver.
x: (*x)(ms),}
err := json.Unmarshal(data,&v)
if err != nil {
return err
}
// Unmarahal raw elements as appropriate.
for _,tcData := range v.TableContents {
if bytes.HasPrefix(tcData,[]byte{'{'}) {
var v TableContentClass
if err := json.Unmarshal(tcData,&v); err != nil {
return err
}
ms.TableContents = append(ms.TableContents,v)
} else {
var v []TableContentClass
if err := json.Unmarshal(tcData,v)
}
}
return nil
}
此方法不会添加任何外部依赖项。在var container MyStruct1
err := json.Unmarshal(result,&container)
if err != nil {
// handle error
}
或MyStruct1
中添加或删除字段时,无需修改功能代码。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。