在我的应用程序中,我得到一些未指定的 json 字符串,并希望循环遍历 json 字符串的值。我使用函数 json.Unmarshal() 从 json 值获取对象列表。效果很好。但不幸的是,我得到了 json 值的随机列表,而不是它们的原始顺序。我使用这个示例代码:
package main
import (
"encoding/json"
"fmt"
)
func main() {
jsonstr := `{
"@odata.context": "http://services.odata.org/V4/TripPinService/$metadata#People/$entity",
"@odata.id": "http://services.odata.org/V4/TripPinService/People('russellwhyte')",
"@odata.etag": "W/\"08D956FAB7E22152\"",
"@odata.editLink": "http://services.odata.org/V4/TripPinService/People('russellwhyte')",
"UserName": "russellwhyte",
"FirstName": "Russell",
"LastName": "Whyte",
"Gender": "Male",
"Concurrency": 637636457076498770
}`
var result interface{}
if err := json.Unmarshal([]byte(jsonstr), &result); err != nil {
fmt.Println("Can't convert json to object.")
fmt.Println(err.Error())
}
odataobjs := result.(map[string]interface{})
for k, v := range odataobjs {
fmt.Print(fmt.Sprintln(k, v))
}
}
Run Code Online (Sandbox Code Playgroud)
请参阅go-playground。
这可能是一些结果列表:
@odata.editLink http://services.odata.org/V4/TripPinService/People('russellwhyte')
UserName russellwhyte
Gender Male
Concurrency 6.376364570764988e+17
@odata.id http://services.odata.org/V4/TripPinService/People('russellwhyte')
@odata.etag W/"08D956FAB7E22152"
LastName Whyte
@odata.context http://services.odata.org/V4/TripPinService/$metadata#People/$entity
FirstName Russell
Run Code Online (Sandbox Code Playgroud)
在 www 中第一次搜索后,我发现 json 对象通常是一个无序列表。这对我来说没问题,只要列表按原始顺序排列即可!我无法构建一些结构,因为 json 值在运行时是未知的!
您有什么想法可以帮助我获得原始价值清单吗?
感谢您的意见。我现在有原始订单。但是:我如何找出值的类型?string、nil int 和 float 都可以,我明白了。但是我如何使用此解决方案找到 json 文件中的数组呢?就像下面的 JSON 一样,他说Emails是未知类型。而且AddressInfo不是listet?所以我无法从中获取子元素。
json输入:
{
"@odata.context": "http://services.odata.org/V4/TripPinService/$metadata#People",
"value": [
{
"@odata.id": "http://services.odata.org/V4/TripPinService/People('vincentcalabrese')",
"@odata.etag": "W/\"08D957CD4BA2C90E\"",
"@odata.editLink": "http://services.odata.org/V4/TripPinService/People('vincentcalabrese')",
"UserName": "vincentcalabrese",
"FirstName": "Vincent",
"LastName": "Calabrese",
"Emails": [
"Vincent@example.com",
"Vincent@contoso.com"
],
"AddressInfo": [
{
"Address": "55 Grizzly Peak Rd.",
"City": {
"CountryRegion": "United States",
"Name": "Butte",
"Region": "MT"
}
}
],
"Gender": "Male",
"Concurrency": 637637361498507534
}
]
}
Run Code Online (Sandbox Code Playgroud)
示例代码:
dec := json.NewDecoder(strings.NewReader(jsonstr))
for dec.More() {
// Read prop name
t, err := dec.Token()
if err != nil {
log.Printf("Err: %v", err)
break
}
var name string
var ok bool
if name, ok = t.(string); !ok {
continue // May be a delimeter
}
// Read value:
t, err = dec.Token()
if err != nil {
log.Printf("Err: %v", err)
break
}
//fmt.Printf("Name: %s, Value: %v\n", name, t)
switch t.(type) {
case nil:
logger.Debug(fmt.Sprintf("%s is nil", name))
case string:
logger.Debug(fmt.Sprintf("%s is string", name))
case []interface{}:
logger.Debug(fmt.Sprintf("%s is array", name))
case map[string]interface{}:
logger.Debug(fmt.Sprintf("%s is map", name))
case int16:
logger.Debug(fmt.Sprintf("%s is int16", name))
case int32:
logger.Debug(fmt.Sprintf("%s is int32", name))
case int64:
logger.Debug(fmt.Sprintf("%s is int64", name))
case float32:
logger.Debug(fmt.Sprintf("%s is float32", name))
case float64:
logger.Debug(fmt.Sprintf("%s is float64", name))
default:
logger.Debug(fmt.Sprintf("%s is unknown type", name))
}
}
Run Code Online (Sandbox Code Playgroud)
输出
@odata.context is string
value is unknown type
@odata.id is string
@odata.etag is string
@odata.editLink is string
UserName is string
FirstName is string
LastName is string
Emails is unknown type
Vincent@example.com is string
Run Code Online (Sandbox Code Playgroud)
你对此有一些想法吗?感谢您。
默认情况下,该encoding/json包使用 Go 映射来解组 JSON 对象。Go 映射没有排序,请参阅为什么 Go 不能按插入顺序迭代映射?在Golang 中,为什么映射的迭代是随机的?
因此,如果您需要原始顺序,则不能使用映射(隐式或显式)。您可以通过令牌使用json.Decoder和解码输入,这当然会按原始顺序为您提供令牌。
这就是您的示例的样子:
dec := json.NewDecoder(strings.NewReader(jsonstr))
for dec.More() {
// Read prop name
t, err := dec.Token()
if err != nil {
log.Printf("Err: %v", err)
break
}
var name string
var ok bool
if name, ok = t.(string); !ok {
continue // May be a delimeter
}
// Read value:
t, err = dec.Token()
if err != nil {
log.Printf("Err: %v", err)
break
}
fmt.Printf("Name: %s, Value: %v\n", name, t)
}
Run Code Online (Sandbox Code Playgroud)
这将输出(在Go Playground上尝试):
Name: @odata.context, Value: http://services.odata.org/V4/TripPinService/$metadata#People/$entity
Name: @odata.id, Value: http://services.odata.org/V4/TripPinService/People('russellwhyte')
Name: @odata.etag, Value: W/"08D956FAB7E22152"
Name: @odata.editLink, Value: http://services.odata.org/V4/TripPinService/People('russellwhyte')
Name: UserName, Value: russellwhyte
Name: FirstName, Value: Russell
Name: LastName, Value: Whyte
Name: Gender, Value: Male
Name: Concurrency, Value: 6.376364570764988e+17
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
835 次 |
| 最近记录: |