因此,我想以某种方式{{ .blahblah }}将模板中定义的所有操作作为字符串切片。
{{ .blahblah }}
例如,如果我有此模板:
<h1>{{ .name }} {{ .age }}</h1>
我希望能够得到[]string{"name", "age"}。假设模板具有方法func (t *Template) Fields() []string:
[]string{"name", "age"}
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"}) }
有没有办法检查这样分析的模板? 谢谢!
前言:正如Voker所建议的,该Template.Tree字段 “仅导出供html / template使用,并且应被所有其他客户端视为未导出”。
Template.Tree
您不应该依赖这种东西来为模板执行提供输入。您必须知道要执行的模板以及所需的数据。您不应在运行时“探索”它来为其提供参数。
您从解析模板中获得的值是template.Template(text/template或html/template,它们具有相同的API)。该模板将模板表示为type的树parse.Tree。文本模板包含的所有内容都存储在此树中的节点中,包括静态文本,操作等。
template.Template
text/template
html/template
parse.Tree
话虽如此,您可以遍历这棵树并查找标识访问字段或调用函数的动作的节点。节点的类型parse.Node具有Node.Type()返回其类型的方法。可能的类型在parse包中定义为常量,紧随该parse.NodeType类型,例如
parse.Node
Node.Type()
parse
parse.NodeType
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. )
因此,这里有一个示例程序,该程序递归地遍历模板树,并查找具有NodeAction类型的节点,即 “非控制性操作,例如字段评估”。
NodeAction
此解决方案仅是演示,是概念证明,不能解决所有情况。
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))
输出(在Go Playground上尝试):
[{{.name}} {{.age}}]