前言:正如Voker所示,Template.Tree
字段爲「僅導出爲HTML /模板使用,應視爲未由所有其他客戶端導出。」
你不應該依靠這樣的事情能夠爲模板的執行提供輸入。你必須知道你想要執行的模板以及它期望的數據。你不應該在運行時「探索」它爲它提供參數。
你走出解析模板的值是template.Template
(無論是text/template
或html/template
,它們具有相同的API)。該模板將模板表示爲parse.Tree
類型的樹。一個文本模板中包含的一切都存儲在此樹中的節點,包括靜態文本,
說了這麼多,你可以走這棵樹,並尋找識別訪問字段或通話功能,動作節點等行動。節點的類型爲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
類型,這是「作爲現場評估這樣的非控制動作。」
這種解決方案只是一個演示,概念證明,它不處理的所有情況。
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}}]
模板包含暴露這種東西(FieldNode)一parse.Tree。形成文檔:「* parse.Tree字段僅導出供html/template使用,並應被視爲未被所有其他客戶端導出。」所以:不要這樣做。如果你不遵循這個建議:祝你好運。 – Volker