2016-11-14 8 views
1

所以我想以某種方式得到所有的模板,串片定義我{{ .blahblah }}行動。Golang,如何從解析後的模板中獲取模板「動作」的地圖或列表?

例如,如果我有這樣的模板:

<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"}) 
} 

有沒有辦法來檢查這樣的分析模板?
謝謝!

+0

模板包含暴露這種東西(FieldNode)一parse.Tree。形成文檔:「* parse.Tree字段僅導出供html/template使用,並應被視爲未被所有其他客戶端導出。」所以:不要這樣做。如果你不遵循這個建議:祝你好運。 – Volker

回答

0

前言:正如Voker所示,Template.Tree字段爲「僅導出爲HTML /模板使用,應視爲未由所有其他客戶端導出。」

你不應該依靠這樣的事情能夠爲模板的執行提供輸入。你必須知道你想要執行的模板以及它期望的數據。你不應該在運行時「探索」它爲它提供參數。


你走出解析模板的值是template.Template(無論是text/templatehtml/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}}] 
+0

感謝您的回答。爲了澄清,您希望在運行時獲取操作的原因是您無法控制模板創建,或者模板經常更改。例如,我有代表字母的模板。我有一個GUI,允許用戶輸入模板的值。顯然,每個模板都會有一些類似的和不同的動作需要填充。因此,GUI需要能夠在運行時顯示模板上發現的每個動作的輸入框,否則我必須靜態編碼每個模板的所有輸入框。 – JackMordaunt