Golang文本模板中如何实现安全导航支持

Golang文本模板中如何实现安全导航支持 我了解到安全导航操作符提案已被否决,但有没有可能在text/template包中支持?.作为操作符呢?

例如,在这个PR中,我添加了使用GitHub CLI用于内置命令输出的相同格式化程序来打印表格的支持。但很多时候,来自GraphQL查询的某些字段是嵌套的,我需要导航到例如.status.message,而.status可能为nil。我可以使用{{if}}动作以及模板其余部分的近似重复内容,但1)这会变得非常笨拙,2)如果有人想要深入多个嵌套节点,情况会更加笨拙。

考虑到text/template已经是它自己的一种特殊小语言,至少提议(甚至可能实现)对安全导航操作符的支持是否可以接受呢?


更多关于Golang文本模板中如何实现安全导航支持的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang文本模板中如何实现安全导航支持的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go的text/template中,目前确实没有内置的安全导航操作符(如?.)。不过,你可以通过自定义函数来实现类似的功能。以下是一个示例,展示如何注册一个自定义函数来安全地访问嵌套字段:

package main

import (
	"os"
	"text/template"
	"reflect"
)

// safeGet 安全获取嵌套字段的值,如果路径中任何部分为nil,则返回nil
func safeGet(data interface{}, path ...string) interface{} {
	v := reflect.ValueOf(data)
	for _, key := range path {
		if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
			if v.IsNil() {
				return nil
			}
			v = v.Elem()
		}
		if v.Kind() != reflect.Map {
			return nil
		}
		v = v.MapIndex(reflect.ValueOf(key))
		if !v.IsValid() {
			return nil
		}
	}
	return v.Interface()
}

func main() {
	// 示例数据
	data := map[string]interface{}{
		"status": map[string]interface{}{
			"message": "Hello, World!",
		},
	}

	// 创建模板并注册自定义函数
	tmpl := template.New("test").Funcs(template.FuncMap{
		"get": safeGet,
	})

	// 解析模板
	tmpl, err := tmpl.Parse(`
{{ $msg := get . "status" "message" }}
{{ if $msg }}
Message: {{ $msg }}
{{ else }}
No message available.
{{ end }}
`)
	if err != nil {
		panic(err)
	}

	// 执行模板
	err = tmpl.Execute(os.Stdout, data)
	if err != nil {
		panic(err)
	}
}

输出:

Message: Hello, World!

如果statusnil,例如:

data := map[string]interface{}{
    "status": nil,
}

输出:

No message available.

这种方法避免了在模板中重复使用{{if}}动作,并允许你安全地访问嵌套字段。虽然这不是一个真正的操作符,但它在功能上提供了类似的安全导航能力。

回到顶部