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}}]
来源:https://stackoverflow.com/questions/40584612/how-to-get-a-map-or-list-of-template-actions-from-a-parsed-template