Golang中如何遍历JSON数据
Golang中如何遍历JSON数据 我正在尝试遍历JSON内容,并以键值对的形式呈现结果。 我目前的基本情况如下:
我有一个 source.hcl 文件
source json "namefile" {
attr firstName {
type = "varchar"
expr = "$.firstName"
length = "30"
}
attr lastName {
type = "varchar"
expr = "$.lastName"
length = "40"
}
attr gender {
type = "varchar"
expr = "$.gender"
length = "10"
}
attr age {
type = "varchar"
expr = "$.age"
length = "2"
}
}
以及一个 target.hcl 文件
target table {
cols firstName {
name=source.json.namefile.attr.firstName.expr
type=source.json.namefile.attr.firstName.type
length=source.json.namefile.attr.firstName.length
}
cols lastName {
name=source.json.namefile.attr.lastName.expr
type=source.json.namefile.attr.lastName.type
length=source.json.namefile.attr.lastName.length
}
}
其中,target.hcl 文件引用了 source.hcl 文件结构中的 name、type 和 length。 读取这些文件后,使用 hcldec.Decode 解码内容,如下所示:
tspec := hcldec.ObjectSpec{
"target": &hcldec.BlockMapSpec{
TypeName: "target",
LabelNames: []string{"table"},
Nested: hcldec.ObjectSpec{
"cols": &hcldec.BlockMapSpec{
TypeName: "cols",
LabelNames: []string{"name"},
Nested: &hcldec.ObjectSpec{
"name": &hcldec.AttrSpec{
Name: "name",
Type: cty.String, //cty.List(cty.String),
Required: false,
},
"type": &hcldec.AttrSpec{
Name: "type",
Type: cty.String, //cty.List(cty.String),
Required: false,
},
"length": &hcldec.AttrSpec{
Name: "length",
Type: cty.String, //cty.List(cty.String),
Required: false,
},
},
},
},
},
}
targ, _ := hcldec.Decode(body, tspec, &hcl.EvalContext{
Variables: map[string]cty.Value{
"source": val.GetAttr("source"),
},
Functions: nil,
})
j := decodeCtyToJson(targ, true)
log.Debugf("targ -j (spec): %s", string(j))
decodeCtyToJson 函数如下:
func decodeCtyToJson(value cty.Value, pretty bool) []byte {
jsonified, err := ctyjson.Marshal(value, cty.DynamicPseudoType)
if err != nil {
log.Debugf("Error: #v", err)
return nil
}
if pretty {
return jsonPretty.Pretty(jsonified)
}
return jsonified
}
最后,我尝试像这样测试打印 JSON 内容:
var result map[string]interface{}
json.Unmarshal(j, &result)
log.Debugf("result: %# v", result)
tgtfil := result["value"].(map[string]interface{})
log.Debugf("tgtfil: %v", tgtfil)
log.Debugf("len(tgtfil): %# v", len(tgtfil))
for key, value := range tgtfil {
log.Debugf("key: %# v", key)
log.Debugf("value: %# v", value)
}
从这些 log.Debugf 调用中,我得到以下输出:
DEBU[0000] targ -j (spec): {
"value": {
"target": {
"table": {
"cols": {
"firstName": {
"length": "30",
"name": "$.firstName",
"type": "varchar"
},
"lastName": {
"length": "40",
"name": "$.lastName",
"type": "varchar"
}
}
}
}
},
"type": [
"object",
{
"target": [
"map",
[
"object",
{
"cols": [
"map",
[
"object",
{
"length": "string",
"name": "string",
"type": "string"
}
]
]
}
]
]
}
]
}
DEBU[0000] result: map[string]interface {}{"type":[]interface {}{"object", map[string]interface {}{"target":[]interface {}{"map", []interface {}{"object", map[string]interface {}{"cols":[]interface {}{"map", []interface {}{"object", map[string]interface {}{"length":"string", "name":"string", "type":"string"}}}}}}}}, "value":map[string]interface {}{"target":map[string]interface {}{"table":map[string]interface {}{"cols":map[string]interface {}{"firstName":map[string]interface {}{"length":"30", "name":"$.firstName", "type":"varchar"}, "lastName":map[string]interface {}{"length":"40", "name":"$.lastName", "type":"varchar"}}}}}}
DEBU[0000] tgtfil: map[target:map[table:map[cols:map[firstName:map[length:30 name:$.firstName type:varchar] lastName:map[length:40 name:$.lastName type:varchar]]]]]
DEBU[0000] len(tgtfil): 1
DEBU[0000] key: "target"
DEBU[0000] value: map[string]interface {}{"table":map[string]interface {}{"cols":map[string]interface {}{"firstName":map[string]interface {}{"length":"30", "name":"$.firstName", "type":"varchar"}, "lastName":map[string]interface {}{"length":"40", "name":"$.lastName", "type":"varchar"}}}}
Process finished with exit code 0
我的目标是能够遍历属性(在本例中是每个 cols 的 length、name 和 type),并能够在程序的后续阶段生成创建表的语句。 但目前我无法提取出这些信息。
任何关于如何实现这一点的建议都将不胜感激。
谢谢, /b
更多关于Golang中如何遍历JSON数据的实战教程也可以访问 https://www.itying.com/category-94-b0.html
感谢你的建议,Terry。 我会研究一下。
祝好。
/b
更多关于Golang中如何遍历JSON数据的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我的解决方案是将目标规范重写为一个结构体。
在Go中遍历JSON数据时,可以使用递归函数来处理嵌套的map结构。以下是针对你当前数据结构的遍历方案:
func traverseJSON(data interface{}) {
switch v := data.(type) {
case map[string]interface{}:
for key, value := range v {
fmt.Printf("Key: %s\n", key)
traverseJSON(value)
}
case []interface{}:
for i, item := range v {
fmt.Printf("Index: %d\n", i)
traverseJSON(item)
}
default:
fmt.Printf("Value: %v\n", v)
}
}
// 针对你的具体数据结构,可以这样提取cols信息:
func extractColsInfo(result map[string]interface{}) {
value := result["value"].(map[string]interface{})
target := value["target"].(map[string]interface{})
table := target["table"].(map[string]interface{})
cols := table["cols"].(map[string]interface{})
for colName, colData := range cols {
fmt.Printf("Column: %s\n", colName)
colInfo := colData.(map[string]interface{})
for attrName, attrValue := range colInfo {
fmt.Printf(" %s: %v\n", attrName, attrValue)
}
}
}
// 更通用的提取函数,可以处理任意深度的嵌套:
func extractAllAttributes(data interface{}, path string) {
switch v := data.(type) {
case map[string]interface{}:
for key, value := range v {
currentPath := path + "." + key
extractAllAttributes(value, currentPath)
}
case []interface{}:
for i, item := range v {
currentPath := fmt.Sprintf("%s[%d]", path, i)
extractAllAttributes(item, currentPath)
}
default:
fmt.Printf("%s = %v\n", path, v)
}
}
// 在你的代码中使用:
func main() {
var result map[string]interface{}
json.Unmarshal(j, &result)
// 方法1:直接提取cols信息
extractColsInfo(result)
// 方法2:递归遍历所有数据
extractAllAttributes(result, "root")
// 方法3:生成建表语句
generateCreateTable(result)
}
func generateCreateTable(result map[string]interface{}) {
value := result["value"].(map[string]interface{})
target := value["target"].(map[string]interface{})
table := target["table"].(map[string]interface{})
cols := table["cols"].(map[string]interface{})
var sqlBuilder strings.Builder
sqlBuilder.WriteString("CREATE TABLE table_name (\n")
first := true
for colName, colData := range cols {
colInfo := colData.(map[string]interface{})
if !first {
sqlBuilder.WriteString(",\n")
}
colType := colInfo["type"].(string)
length := colInfo["length"].(string)
sqlBuilder.WriteString(fmt.Sprintf(" %s %s(%s)",
colName, colType, length))
first = false
}
sqlBuilder.WriteString("\n);")
fmt.Println(sqlBuilder.String())
}
对于你的具体需求,这里是一个专门处理target.hcl结构的函数:
func processTargetConfig(result map[string]interface{}) []map[string]string {
var columns []map[string]string
value := result["value"].(map[string]interface{})
target := value["target"].(map[string]interface{})
for tableName, tableData := range target {
table := tableData.(map[string]interface{})
cols := table["cols"].(map[string]interface{})
for colName, colData := range cols {
colInfo := colData.(map[string]interface{})
column := map[string]string{
"table": tableName,
"column": colName,
"name": colInfo["name"].(string),
"type": colInfo["type"].(string),
"length": colInfo["length"].(string),
}
columns = append(columns, column)
}
}
return columns
}
// 使用示例:
columns := processTargetConfig(result)
for _, col := range columns {
fmt.Printf("Table: %s, Column: %s\n", col["table"], col["column"])
fmt.Printf(" JSON Path: %s\n", col["name"])
fmt.Printf(" Data Type: %s(%s)\n", col["type"], col["length"])
}
这个方案可以直接处理你当前的JSON结构,提取出所有列的元数据信息,并可以用于生成创建表的SQL语句。

