英文:
Json unmarshal: force into string
问题
我有以下的Go结构体,我想要将一些Json数据解析到其中。除了Values
这个类型为map[string]string
的map之外,其他都可以正常工作。
type Data struct {
Id int `json:"id"`
Values map[string]string `json:"values"`
}
我的Json数据(无法更改格式)具有以下结构和示例数据:
{
"id": 1,
"values": {
"key1": "a string value",
"key2": 7
}
}
解析Json数据失败,因为Go无法将值7
解析为字符串。
json: cannot unmarshal number into Go struct field Data.Values of type string
是否有一种方法可以将Json值隐式转换为字符串,而不考虑其感知类型?将Json数据更改为将值格式化为字符串,例如key2: "7"
,不是一个选项。
英文:
I have the following Go struct into which I want to unmarshal some Json data. It works perfectly except for the Values
map, which is of type map[string]string
.
type Data struct {
Id int `jons:"id"`
Values map[string]string `json:"values"`
My Json data (which I can't change the format of), has the following structure and sample data:
{
id: 1,
values: {
key1: "a string value",
key2: 7
}
}
Unmarshalling the json data fails because Go can't unmarshal the value 7
into a string.
json: cannot unmarshal number into Go struct field Data.Values of type string
Is there a way to implicitly convert the Json values into a string, regardless of the perceived type?
Changing the Json data to format the value as a string, ie key2: "7"
is not an option.
答案1
得分: 3
由于JSON中可以包含整数或字符串,如果您使用接口会更好。
类似这样:
type Data struct {
Id int `json:"id"`
Values map[string]interface{} `json:"values"`
}
这样应该可以解决问题。
参考示例代码:
https://play.golang.org/p/PjxWeLTwsCC
英文:
Since you can have an integer or a string in the json, it would be better if you use an interface.
Something like this:
type Data struct {
Id int `jons:"id"`
Values map[string]interface{} `json:"values"`
}
This should do the trick.
Sample code for reference:
https://play.golang.org/p/PjxWeLTwsCC
答案2
得分: 2
你可以创建自己的字符串类型,并实现UnmarshalJSON函数。
type MadString string
type Data struct {
Id int `json:"id"`
Values map[string]MadString `json:"values"`
}
func (mad *MadString) UnmarshalJSON(data []byte) error {
if n := len(data); n > 1 && data[0] == '"' && data[n-1] == '"' {
return json.Unmarshal(data, (*string)(mad))
}
*mad = MadString(data)
return nil
}
示例:https://play.golang.org/p/PsJRsvQJPMZ
英文:
You can create own string type and implement UnmarshalJSON function to it.
type MadSrting string
type Data struct {
Id int `jons:"id"`
Values map[string]MadString `json:"values"`
}
func (mad *MadString) UnmarshalJSON(data []byte) error {
if n := len(data); n > 1 && data[0] == '"' && data[n-1] == '"' {
return json.Unmarshal(data, (*string)(mad))
}
*mad = MadString(data)
return nil
}
答案3
得分: 1
你可以使用接口和类型断言。
package main
import (
"encoding/json"
"fmt"
"strconv"
)
func main() {
type Data struct {
Id int `json:"id"`
Values map[string]interface{} `json:"values"`
}
jsonData := []byte(`{"id": 1, "values": {"key1": "a string value", "key2": 7}}`)
data := new(Data)
err := json.Unmarshal(jsonData, &data)
if err != nil {
fmt.Println(err)
}
for _, value := range data.Values {
fmt.Printf("%T\n", ToString(value))
}
}
func ToString(value interface{}) string {
str := ""
switch value.(type) {
case float64:
str = strconv.FormatFloat(value.(float64), 'f', 0, 64)
case int64:
str = strconv.FormatInt(value.(int64), 10)
case int:
str = strconv.Itoa(value.(int))
case string:
str = value.(string)
}
return str
}
https://play.golang.org/p/r9_6IKRgPst
英文:
You can use interface and type assertions
<pre>
package main
import (
"encoding/json"
"fmt"
"strconv"
)
func main() {
type Data struct {
Id int jons:"id"
Values map[string]interface{} json:"values"
}
jsonData := []byte(`{"id": 1, "values": {"key1": "a string value", "key2": 7}}`)
data := new(Data)
err := json.Unmarshal(jsonData, &data)
if err != nil {
fmt.Println(err)
}
for _, value := range data.Values {
fmt.Printf("%T\n", ToString(value))
}
}
func ToString(value interface{}) string {
str := ""
switch value.(type) {
case float64:
str = strconv.FormatFloat(value.(float64), 'f', 0, 64)
case int64:
str = strconv.FormatInt(value.(int64), 10)
case int:
str = strconv.Itoa(value.(int))
case string:
str = value.(string)
}
return str
}
</pre>
答案4
得分: 1
为了总结提供的答案,基本上有三种方法:
-
使用自定义类型值的映射,该类型“包装”了
string
并实现了encoding/json.Unmarshaler
接口,以便在解析JSON文档中的值时可以灵活处理。 -
将子文档解组为
map[string]interface{}
类型的映射,然后在每次访问该值时使用类型切换,或者从结果映射中填充其他数据类型(在您的情况下可能是map[string]string
),无论哪种情况都将使用类型切换。 -
使用较低级别的JSON解码工具——
encoding/json.Decoder
——并在解码阶段决定如何解码特定值,并生成一个string
,无论被解析的值实际上是哪种类型。
英文:
To round up the provided answers, there exist basically three approaches:
-
Use a map of custom-typed values, whose type "wraps"
string
and implements anencoding/json.Unmarshaler
interface to be creative about how it parses the values from the JSON document. -
Unmarshal the subdocument into a map of type
map[string]interface{}
and then either use type-switching on the value on each access to such value or populate some other data type — supposedlymap[string]string
in your case — from the resulting map (you'll be using type-switching in either case). -
Use a lower-level JSON decoding facilities —
encoding/json.Decoder
— and make decision about how to decode a particular value at decoding phase, and produce astring
no matter which type the value being parsed really is.
答案5
得分: 0
你可以在地图值上使用空接口(empty interface)。然后使用Sprintf将其转换为字符串。以下是一个示例,展示了如何解组你的数据:
package main
import (
"encoding/json"
"fmt"
)
type Data struct {
Id int `json:"id"`
Values map[string]interface{} `json:"values"`
}
func main() {
data := `
{
"id": 1,
"values": {
"key1": "a string value",
"key2": 7
}
}
`
var d Data
err := json.Unmarshal([]byte(data), &d)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(d)
s1 := fmt.Sprintf("%v", d.Values["key1"])
fmt.Println("key1", s1)
s2 := fmt.Sprintf("%v", d.Values["key2"])
fmt.Println("key2", s2)
}
希望对你有帮助!
英文:
You can use the empty interface on your maps values. An then convert it to a string with Sprintf. Here is an example of how you could unmarshal your data:
package main
import (
"encoding/json"
"fmt"
)
type Data struct {
Id int `jons:"id"`
Values map[string]interface{} `json:"values"`
}
func main() {
data := `
{
"id": 1,
"values": {
"key1": "a string value",
"key2": 7
}
}
`
var d Data
err := json.Unmarshal([]byte(data), &d)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(d)
s1 := fmt.Sprintf("%v", d.Values["key1"])
fmt.Println("key1", s1)
s2 := fmt.Sprintf("%v", d.Values["key2"])
fmt.Println("key2", s2)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论