Golang中如何优雅地格式化JSON
Golang中如何优雅地格式化JSON 我有一堆JSON对象想要打印到屏幕上。 我希望对键进行排序,以便更容易阅读。 这段Python代码实现了我的需求:
#!/usr/bin/env python3
import json
def reorder(s):
o = json.loads(s)
return json.dumps(o, sort_keys=True)
input1 = '{"b": 2, "A":1, "c": {"d": 3}}'
input2 = '{"c": {"d": 3}, "b": 2, "A":1}'
print(input1)
print(input2)
print()
print(reorder(input1))
print(reorder(input2))
输出:
{"b": 2, "A":1, "c": {"d": 3}}
{"c": {"d": 3}, "b": 2, "A":1}
{"A": 1, "b": 2, "c": {"d": 3}}
{"A": 1, "b": 2, "c": {"d": 3}}
我尝试使用json.Unmarshal和json.Marshal,但它会过滤掉小写键。 而且输出中没有空格,这有点难以阅读。
我事先不知道消息的格式。 我只知道它们将是JSON对象。
有人有好的方法来实现这个吗?
更多关于Golang中如何优雅地格式化JSON的实战教程也可以访问 https://www.itying.com/category-94-b0.html
感谢。 那里有很多有用的信息,但大多数答案都将 JSON 打印在多行上。我需要它全部在一行上。
谢谢。 jq 是个好主意。我可以用它,但如果可能的话,更倾向于一个纯 Go 的解决方案,不依赖外部库。
MikeSolem: 有人有好的方法来做这个吗?
如何使用 Go 漂亮地打印 JSON?
标签: json, go, pretty-print
由 Brad Peabody 提问于 08:59PM - 26 Sep 13 UTC
要美化打印你的JSON,你可以简单地使用 MarshalIndent 而不是 Marshal 函数。关于重新排序,是的,你可以设想一个函数来实现这一点,但请记住,JSON是一种用于数据交换的格式,元素的顺序无法保证,也不应成为关注点。
JSON数据交换标准在 json.org 上的定义明确指出:“对象是一个无序的[强调为我所加]名称/值对集合”,而数组是“值的有序集合”。换句话说,根据定义,JSON对象内部键/值对的顺序根本无关紧要,也不应该重要。
我在原始问题中犯了一个错误。
json.Unmarshal 和 json.Marshal 并不会过滤掉小写键。
它只是把小写的内容放到了末尾,所以我在输出中没有看到。
所以这段代码正确地进行了字母顺序排序。
package main
import (
"encoding/json"
"fmt"
)
func reorder(obj string) string {
var o map[string]interface{}
json.Unmarshal([]byte(obj), &o)
r, _ := json.Marshal(o)
return string(r)
}
func main() {
input1 := `{"b": 2, "A":1, "c": {"d": 3}}`
input2 := `{"c": {"d": 3}, "b": 2, "A":1}`
fmt.Println(input1)
fmt.Println(input2)
fmt.Println()
fmt.Println(reorder(input1))
fmt.Println(reorder(input2))
}
输出:
{"b": 2, "A":1, "c": {"d": 3}}
{"c": {"d": 3}, "b": 2, "A":1}
{"A":1,"b":2,"c":{"d":3}}
{"A":1,"b":2,"c":{"d":3}}
如果每个冒号和逗号后面都有一个空格,可读性会好得多。
在Go中可以使用json.MarshalIndent配合自定义排序来实现JSON的优雅格式化。以下是示例代码:
package main
import (
"encoding/json"
"fmt"
"sort"
)
func formatJSON(input string) (string, error) {
var data map[string]interface{}
if err := json.Unmarshal([]byte(input), &data); err != nil {
return "", err
}
// 递归排序所有嵌套map的键
sortKeys(data)
// 使用MarshalIndent添加缩进和换行
formatted, err := json.MarshalIndent(data, "", " ")
if err != nil {
return "", err
}
return string(formatted), nil
}
func sortKeys(m map[string]interface{}) {
// 先对当前层级的键进行排序
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
// 创建新的有序map
sorted := make(map[string]interface{})
for _, k := range keys {
sorted[k] = m[k]
// 递归处理嵌套的map
if nested, ok := m[k].(map[string]interface{}); ok {
sortKeys(nested)
}
}
// 将排序后的内容复制回原map
for k, v := range sorted {
m[k] = v
}
}
func main() {
inputs := []string{
`{"b": 2, "A":1, "c": {"d": 3}}`,
`{"c": {"d": 3}, "b": 2, "A":1}`,
}
for _, input := range inputs {
fmt.Println("原始JSON:")
fmt.Println(input)
formatted, err := formatJSON(input)
if err != nil {
fmt.Printf("错误: %v\n", err)
continue
}
fmt.Println("\n格式化后:")
fmt.Println(formatted)
fmt.Println()
}
}
输出结果:
原始JSON:
{"b": 2, "A":1, "c": {"d": 3}}
格式化后:
{
"A": 1,
"b": 2,
"c": {
"d": 3
}
}
原始JSON:
{"c": {"d": 3}, "b": 2, "A":1}
格式化后:
{
"A": 1,
"b": 2,
"c": {
"d": 3
}
}
如果需要处理JSON数组或更复杂的嵌套结构,可以使用以下扩展版本:
func sortKeysRecursive(v interface{}) {
switch val := v.(type) {
case map[string]interface{}:
// 排序当前map的键
keys := make([]string, 0, len(val))
for k := range val {
keys = append(keys, k)
}
sort.Strings(keys)
sorted := make(map[string]interface{})
for _, k := range keys {
sorted[k] = val[k]
// 递归处理值
sortKeysRecursive(val[k])
}
// 更新原map
for k, v := range sorted {
val[k] = v
}
case []interface{}:
// 处理数组中的每个元素
for _, item := range val {
sortKeysRecursive(item)
}
}
}
func formatJSONAdvanced(input string) (string, error) {
var data interface{}
if err := json.Unmarshal([]byte(input), &data); err != nil {
return "", err
}
sortKeysRecursive(data)
formatted, err := json.MarshalIndent(data, "", " ")
if err != nil {
return "", err
}
return string(formatted), nil
}
这个实现会:
- 保持所有键(包括大小写敏感)
- 按键名排序(Go的
sort.Strings按字典序排序) - 使用两个空格缩进格式化输出
- 递归处理嵌套的JSON对象和数组



