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

4 回复

感谢你的建议,Terry。 我会研究一下。

祝好。

/b

更多关于Golang中如何遍历JSON数据的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我的解决方案是将目标规范重写为一个结构体。

也许这个包能帮上忙:

GitHub

thedevsaddam/gojsonq

一个简单的 Go 包,用于查询 JSON/YAML/XML/CSV 数据 - thedevsaddam/gojsonq

在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语句。

回到顶部