如何从已解析的模板中获取映射或模板“操作”列表?

问题描述 投票:2回答:2

所以我想以某种方式将模板中定义的所有{{ .blahblah }}操作作为字符串切片。

例如,如果我有此模板:

<h1>{{ .name }} {{ .age }}</h1>

我希望能够获得[]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"})
}

是否有办法检查这样分析的模板?谢谢!

templates go go-templates
2个回答
4
投票

[序言:如Voker所建议,Template.Tree字段为“仅导出供html / template使用,应被所有其他客户端视为未导出。”

您不应该依赖这种东西来为模板执行提供输入。您必须知道要执行的模板及其期望的数据。您不应该在运行时“探索”它来为其提供参数。


您从解析模板中得到的值是template.Templatetemplate.Templatetext/template,它们具有相同的API)。该模板将模板表示为类型为html/template的树。文本模板包含的所有内容都存储在此树中的节点中,包括静态文本,操作等。

话虽如此,您可以遍历这棵树并查找标识访问字段或调用函数的此类动作的节点。节点的类型为parse.Tree,该节点具有返回其类型的parse.Tree方法。可能的类型在parse.Node包中定义为常量,在parse.Node类型旁边,例如

Node.Type()

因此这是一个示例程序,该程序递归地遍历模板树,并查找具有parse类型的节点,这是“非控制动作,例如字段评估。”

此解决方案仅是演示,是概念证明,不能解决所有情况。

parse.NodeType

使用示例:

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

0
投票

我碰巧需要大致相同的代码。在我的用例中,我们允许用户在一侧创建模板,并输入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 } 变量以不同的形式呈现。

这是我到目前为止提出的代码(受icza的回答启发:

t := template.Must(template.New("cooltemplate").
    Parse(`<h1>{{ .name }} {{ .age }}</h1>`))
fmt.Println(ListTemplFields(t))

Go Playground

© www.soinside.com 2019 - 2024. All rights reserved.