Richard Bucker

parsing go templates

Posted at — Sep 1, 2015

Given a template file I want to parse out some variables so that I can prompt the user but I do not want to build my own parser or some set of regex although after playing with the go templates and parse tree it might be the best thing to do since I’m already making the syntax simple.My simple document looks like this:doc := “fred {{.Fred}} barney"Here’s my sample code (playground):package mainimport ( “html/template” “log”)func main() { doc := “fred {{.Fred}} barney" t := template.Must(template.New(“sample”).Parse(doc)) log.Printf("%#v”, t) log.Printf("%#v”, t.Tree.Root) log.Printf("%#v", t.Tree.Root.Nodes) for _, n := range t.Tree.Root.Nodes { log.Printf("%#v", n) if n.Type() == 1 { log.Printf("%s", n) } }}The output was interesting but as I expected and similar to the sort of parsing I was thinking about and was demonstrated by Rob Pike in his Lexer video. The downside of using the template parser is that it’s going to parse a lot more than the simple (did I say that again) DSL I had in mind even though it’s based on the go templates.This is the logging that I performed before the for look. There is nothing particularly interesting here.2009/11/10 23:00:00 &template.Template{escapeErr:error(nil), text:(*template.Template)(0x105345c0), Tree:(*parse.Tree)(0x10583a40), nameSpace:(*template.nameSpace)(0x10538360)}2009/11/10 23:00:00 &parse.ListNode{NodeType:11, Pos:0, tr:(*parse.Tree)(0x10583a40), Nodes:[]parse.Node{(*parse.TextNode)(0x105346e0), (*parse.ActionNode)(0x10534740), (*parse.TextNode)(0x10534760)}}2009/11/10 23:00:00 []parse.Node{(*parse.TextNode)(0x105346e0), (*parse.ActionNode)(0x10534740), (*parse.TextNode)(0x10534760)}Here are the 3 nodes that were parsed. It essentially comes down to “fred”, “{{.Fred}}”, " barney". Since I was only interested in the actionnode I checked for it Type()==1 and then printed the name. I thought that I might get the inner part but then I realized that the parser need to look inside and pull more tokens out… the template schema is a DSL unto itself.2009/11/10 23:00:00 &parse.TextNode{NodeType:0, Pos:0, tr:(*parse.Tree)(0x10583a40), Text:[]uint8{0x66, 0x72, 0x65, 0x64, 0x20}}2009/11/10 23:00:00 &parse.ActionNode{NodeType:1, Pos:7, tr:(*parse.Tree)(0x10583a40), Line:1, Pipe:(*parse.PipeNode)(0x1053a1b0)}2009/11/10 23:00:00 {{.Fred}}2009/11/10 23:00:00 &parse.TextNode{NodeType:0, Pos:14, tr:(*parse.Tree)(0x10583a40), Text:[]uint8{0x20, 0x62, 0x61, 0x72, 0x6e, 0x65, 0x79}}There is a lot of stuff in the parsed doc. It might be simple to locate the pieces I’m looking for. But this is a start.