Golang中如何自定义多层映射的JSON序列化

Golang中如何自定义多层映射的JSON序列化 我编写了一些代码,用于将JSON数据自定义反序列化到 map[string]map[string]*template.Template 中。反序列化器负责解析模板数据,这意味着特定模板很可能出现错误。在这种情况下,我希望向用户返回一个带有两个字符串键注释的错误,以便用户知道是哪个模板失败了。

我已经编写了代码(https://play.golang.org/p/4Fi9i3fphuo),效果相当不错,但我不禁思考是否有更简洁或更高效的方法来实现这一点。我能看到的一个问题是,在递归调用 json.Unmarshal() 之前,我需要重新序列化来自 map[string]interface{}interface{} 数据(参见注释)。这似乎效率不高……有没有更好的方法?

我希望为所有三个层级保留自定义反序列化器,因为我希望能够将其他JSON数据反序列化到 map[string]*template.Template 中。

对此有什么想法吗……?

func main() {
    fmt.Println("hello world")
}

更多关于Golang中如何自定义多层映射的JSON序列化的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中如何自定义多层映射的JSON序列化的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中处理嵌套映射的自定义JSON反序列化时,确实可以优化避免中间重新序列化的步骤。以下是改进后的实现方案:

package main

import (
	"encoding/json"
	"fmt"
	"text/template"
)

type TemplateMap map[string]*template.Template

func (tm *TemplateMap) UnmarshalJSON(data []byte) error {
	var raw map[string]string
	if err := json.Unmarshal(data, &raw); err != nil {
		return err
	}
	
	*tm = make(TemplateMap)
	for key, text := range raw {
		tpl, err := template.New(key).Parse(text)
		if err != nil {
			return fmt.Errorf("template '%s': %w", key, err)
		}
		(*tm)[key] = tpl
	}
	return nil
}

type NestedTemplateMap map[string]TemplateMap

func (ntm *NestedTemplateMap) UnmarshalJSON(data []byte) error {
	var raw map[string]json.RawMessage
	if err := json.Unmarshal(data, &raw); err != nil {
		return err
	}
	
	*ntm = make(NestedTemplateMap)
	for outerKey, innerData := range raw {
		var innerMap TemplateMap
		if err := json.Unmarshal(innerData, &innerMap); err != nil {
			return fmt.Errorf("outer key '%s': %w", outerKey, err)
		}
		(*ntm)[outerKey] = innerMap
	}
	return nil
}

func main() {
	jsonData := `{
		"group1": {
			"template1": "Hello {{.Name}}",
			"template2": "Welcome {{.User}}"
		},
		"group2": {
			"template3": "Error: {{.Msg}}"
		}
	}`

	var result NestedTemplateMap
	if err := json.Unmarshal([]byte(jsonData), &result); err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}

	// 验证模板
	for outerKey, innerMap := range result {
		for innerKey, tpl := range innerMap {
			fmt.Printf("Key: %s.%s, Template: %v\n", outerKey, innerKey, tpl)
		}
	}
}

这个实现的关键改进:

  1. 使用 json.RawMessage 避免中间重新序列化,直接处理原始JSON数据
  2. 分层自定义反序列化
    • TemplateMap 处理内层映射 map[string]*template.Template
    • NestedTemplateMap 处理外层映射 map[string]TemplateMap
  3. 精确的错误定位:在两层反序列化中都提供了具体的键名信息

当模板解析失败时,错误信息会清晰地指出具体是哪个外层键和内层键的组合出现了问题,例如:"outer key 'group1': template 'template1': ..."

这种方法既保持了代码的简洁性,又提供了良好的错误信息和性能表现。

回到顶部