此解决方案仅是演示,是概念证明,不能解决所有情况.func ListTemplFields(t *template.Template) []string { return listNodeFields(t.Tree.Root, nil)}func listNodeFields(node parse.Node, res []string) []string { if node.Type() == parse.NodeAction { res = append(res, node.String()) } if ln, ok := node.(*parse.ListNode); ok { for _, n := range ln.Nodes { res = listNodeFields(n, res) } } return res}使用示例:t := template.Must(template.New("cooltemplate"). Parse(`<h1>{{ .name }} {{ .age }}</h1>`))fmt.Println(ListTemplFields(t))输出(在进入游乐场上尝试):[{{.name}} {{.age}}]So I would like to somehow get all of my {{ .blahblah }} actions defined in a template as slice of strings. For example if I have this template: <h1>{{ .name }} {{ .age }}</h1>I would like to be able to get []string{"name", "age"}. Pretend that a template has the method func (t *Template) Fields() []string:t := template.New("cooltemplate").Parse(`<h1>{{ .name }} {{ .age }}</h1>`)if t.Fields() == []string{"name", "age"} { fmt.Println("Yay, now I know what fields I can pass in!") // Now lets pass in the name field that we just discovered. _ = t.Execute(os.Stdout, map[string]string{"name": "Jack", "age":"120"})}Is there a way to inspect a parsed template like this?Thanks! 解决方案 Foreword: As Voker suggests, the Template.Tree field is "exported only for use by html/template and should be treated as unexported by all other clients."You should not rely on such thing to be able to provide input for a template execution. You must know the template you want to execute along with the data it expects. You shouldn't "explore" it at runtime to provide arguments for it.The value you get out of parsing a template is template.Template (either text/template or html/template, they have the same API). This template represents the templates as a tree of type parse.Tree. Everything that a text template contains is stored in this tree in nodes, including static texts, actions etc.Having said that, you can walk this tree and look for nodes that identify such actions that access fields or call functions. The nodes are of type parse.Node which has a Node.Type() method returning its type. The possible types are defined as constants in the parse package, next to the parse.NodeType type, e.g.const ( NodeText NodeType = iota // Plain text. NodeAction // A non-control action such as a field evaluation. NodeBool // A boolean constant. NodeChain // A sequence of field accesses. NodeCommand // An element of a pipeline. NodeDot // The cursor, dot. NodeField // A field or method name. NodeIdentifier // An identifier; always a function name. NodeIf // An if action. NodeList // A list of Nodes. NodeNil // An untyped nil constant. NodeNumber // A numerical constant. NodePipe // A pipeline of commands. NodeRange // A range action. NodeString // A string constant. NodeTemplate // A template invocation action. NodeVariable // A $ variable. NodeWith // A with action.)So here is an example program that recursively walks a template tree, and looks for nodes with NodeAction type, which is "A non-control action such as a field evaluation."This solution is just a demonstration, a proof of concept, it does not handle all cases.func ListTemplFields(t *template.Template) []string { return listNodeFields(t.Tree.Root, nil)}func listNodeFields(node parse.Node, res []string) []string { if node.Type() == parse.NodeAction { res = append(res, node.String()) } if ln, ok := node.(*parse.ListNode); ok { for _, n := range ln.Nodes { res = listNodeFields(n, res) } } return res}Example using it:t := template.Must(template.New("cooltemplate"). Parse(`<h1>{{ .name }} {{ .age }}</h1>`))fmt.Println(ListTemplFields(t))Output (try it on the Go Playground):[{{.name}} {{.age}}] 这篇关于如何从已解析的模板获取地图或模板“动作"列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
10-29 17:11