JSON值的原始顺序

  • 本文关键字:顺序 原始 JSON json go
  • 更新时间 :
  • 英文 :


在我的应用程序中,我得到一些未指定的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))
}
}

See on 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

在www中第一次搜索后,我发现,json对象通常是一个无序列表。这对我来说没问题,只要列表是按原来的顺序排列的!我不能建立一些结构,因为json值在运行时是未知的!

你有什么主意让我拿到原始价值清单吗?

感谢您的输入。我现在有原来的订单。但是:我怎样才能找出值的类型?字符串,nil int和float都没问题,我得到了这个。但我怎么能找到这个解决方案的json文件中的数组?就像下面的JSON一样,他说email是一个未知类型。和AddressInfo不是列表?所以我不能从中获取子元素

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
}
]
}

示例代码:

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: %vn", 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))
}
}

输出
@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
你有什么主意吗?谢谢你。

默认情况下,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: %vn", name, t)
}

这将输出(在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

而不是得到json随机列表,你可以得到它在升序使用sort包。您需要创建映射键的切片并对其使用sort.Strings()方法,然后可以迭代切片并按升序获取数据。下面是相同的代码:

package main
import (
"encoding/json"
"fmt"
"sort"
)
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{})
keysJson := make([]string, 0, len(odataobjs))
for k := range odataobjs {
keysJson = append(keysJson, k)
}
sort.Strings(keysJson)
for _, k2 := range keysJson {
fmt.Println(k2, odataobjs[k2])
}
}

输出:

@odata.context http://services.odata.org/V4/TripPinService/$metadata#People/$entity
@odata.editLink http://services.odata.org/V4/TripPinService/People('russellwhyte')
@odata.etag W/"08D956FAB7E22152"
@odata.id http://services.odata.org/V4/TripPinService/People('russellwhyte')
Concurrency 6.376364570764988e+17
FirstName Russell
Gender Male
LastName Whyte
UserName russellwhyte

最新更新