go json unmarshal options的中文翻译是”go JSON解析选项”。

huangapple go评论76阅读模式
英文:

go json unmarshal options

问题

尝试找到一个简单的解决方案来将数据解析成以下结构:

type Resource struct {
    Data []ResourceData `json:"data"`
}
type ResourceData struct {
    Id           string                 `json:"id"`
    Type         string                 `json:"type"`
    Attributes   map[string]interface{} `json:"attributes"`
    Relationships map[string]Resource   `json:"relationships"`
}
r := Resource{}
json.Unmarshal(body, &r)

如果body的值为{"data":[{"id":"1","type":"blah"}]},那么这个解决方案是有效的。

然而,我还需要它能够处理以下情况:

body = `{"data":{"id":"1","type":"blah"}}` // 注意没有切片

我可以创建一个单独的类型:

type ResourceSingle struct {
    Data ResourceData `json:"data"`
}

然而,这意味着我需要复制所有附加到resource的函数,这是可能的。然而,我需要在执行之前找出要解析成哪种类型,而且当涉及到关系部分时,每个关系都可以包含data:[]data{},所以这个想法行不通。

另一种方法是使用:

map[string]*json.RawMessage
// 或者
type Resource struct {
    Data *json.RawMessage `json:"data"`
}

但是,当以JSON形式存在时,我如何知道它是一个切片还是一个节点,以便提供正确的结构进行解析?

我最后的选择是将其解析为map[string]interface{},然后使用大量的反射测试...但这样非常冗长。

有什么想法吗?

谢谢,jJ

英文:

Trying to find a simple solution to marshaling/unmashaling into the following struct

type Resource struct {
	Data []ResourceData `json:"data"`
}
type ResourceData struct {
	Id string  `json:"id"`
	Type string  `json:"type"`
	Attributes map[string]interface{} `json:"attributes"`
	Relationships map[string]Resource `json:"relationships"`
}
r := Resource{}
json.Unmarshal(body, &r)

this is great if:

body = `{"data":[{"id":"1","type":"blah"}]}`

However I also need it to respond to:

body = `{"data":{"id":"1","type":"blah"}}` //notice no slice

I could make a separate type

type ResourceSingle struct {
	Data ResourceData `json:"data"`
}

However, that would mean needing to duplicate all the functions I have attached to resource, which is possible. However, i would need to find out which type to unmarshal into before executing it, plus when it comes to the relationships part, each of those could contain data:[]{} or data{}, so that idea isn't going to work.

Alternatively I could use

map[string]*json.RawMessage
//or
type Resource struct {
	Data *json.RawMessage `json:"data"`
}

but still, when in json form how do I know if it is a slice or a node to supply the correct struct to unmarshal into?

My last resort is to umarshal into map[string]interface and use lots of reflect testing .. but this is very long winded.

Ideas?

Kind regards, jJ

答案1

得分: 2

有多种方法可以对其进行结构化,但最简单的技术是实现json.Unmarshaler,并检查数据的类型。你可以最小程度地解析JSON字节,通常只需解析第一个字符,或者尝试将其解组为每种类型并返回成功的类型。

在这里,我们将使用后一种技术,无论传入数据的格式如何,都将ResourceData插入到一个切片中,以便我们始终可以以相同的方式操作它:

type Resource struct {
    Data []ResourceData
}

func (r *Resource) UnmarshalJSON(b []byte) error {
    // 这给了我们一个临时位置来解组
    m := struct {
        DataSlice struct {
            Data []ResourceData `json:"data"`
        }
        DataStruct struct {
            Data ResourceData `json:"data"`
        }
    }{}

    // 尝试使用切片解组数据
    err := json.Unmarshal(b, &m.DataSlice)
    if err == nil {
        log.Println("got slice")
        r.Data = m.DataSlice.Data
        return nil
    } else if err, ok := err.(*json.UnmarshalTypeError); !ok {
        // 发生了除类型错误之外的其他错误
        return err
    }

    // 尝试使用结构体解组数据
    err = json.Unmarshal(b, &m.DataStruct)
    if err != nil {
        return err
    }
    log.Println("got struct")

    r.Data = append(r.Data, m.DataStruct.Data)
    return nil
}

你可以在这里查看示例代码:http://play.golang.org/p/YIPeYv4AfT

英文:

There's a number of ways to structure it, but the simplest technique comes down to implementing a json.Unmarshaler, and inspecting the type of the data. You can minimally parse the json bytes, often just the first character, or you can try to unmarshal into each type and return the one that succeeds.

We'll use the latter technique here, and insert the ResourceData into a slice regardless of the incoming data's format, so we can always operate on it in the same manner:

type Resource struct {
	Data []ResourceData
}

func (r *Resource) UnmarshalJSON(b []byte) error {
	// this gives us a temporary location to unmarshal into
	m := struct {
		DataSlice struct {
			Data []ResourceData `json:"data"`
		}
		DataStruct struct {
			Data ResourceData `json:"data"`
		}
	}{}

	// try to unmarshal the data with a slice
	err := json.Unmarshal(b, &m.DataSlice)
	if err == nil {
		log.Println("got slice")
		r.Data = m.DataSlice.Data
		return nil
	} else if err, ok := err.(*json.UnmarshalTypeError); !ok {
		// something besides a type error occurred
		return err
	}

	// try to unmarshal the data with a struct
	err = json.Unmarshal(b, &m.DataStruct)
	if err != nil {
		return err
	}
	log.Println("got struct")

	r.Data = append(r.Data, m.DataStruct.Data)
	return nil
}

http://play.golang.org/p/YIPeYv4AfT

huangapple
  • 本文由 发表于 2015年11月6日 22:37:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/33569210.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定