问题
This is my directory structure:
app/
template/
layout/
base.tmpl
index.tmpl
template.ParseGlob("*/*.tmpl")
parses index.tmpl
but not base.tmpl
in the layout
subdirectory. Is there a way to parse all templates recursively?
回答1:
Not without implementing your own function to do it, I've been using something like this
func ParseTemplates() *template.Template {
templ := template.New("")
err := filepath.Walk("./views", func(path string, info os.FileInfo, err error) error {
if strings.Contains(path, ".html") {
_, err = templ.ParseFiles(path)
if err != nil {
log.Println(err)
}
}
return err
})
if err != nil {
panic(err)
}
return templ
}
This will parse all your templates then you can render them by calling their names e.g.
template.ExecuteTemplate(w, "home", nil)
回答2:
Datsik's answer has the drawback that there are name collision issues when several directories contain many templates. If two templates in different directories have the same filename it won't work properly: only the second of them will be usable.
This is caused by the implementation of template.ParseFiles, so we can solve it by avoiding template.ParseFiles. Here's a modified walk algorithm that does this by using template.Parse directly instead.
func findAndParseTemplates(rootDir string, funcMap template.FuncMap) (*template.Template, error) {
cleanRoot := filepath.Clean(rootDir)
pfx := len(cleanRoot)+1
root := template.New("")
err := filepath.Walk(cleanRoot, func(path string, info os.FileInfo, e1 error) error {
if !info.IsDir() && strings.HasSuffix(path, ".html") {
if e1 != nil {
return e1
}
b, e2 := ioutil.ReadFile(path)
if e2 != nil {
return e2
}
name := path[pfx:]
t := root.New(name).Funcs(funcMap)
_, e2 = t.Parse(string(b))
if e2 != nil {
return e2
}
}
return nil
})
return root, err
}
This will parse all your templates then you can render them by calling their names e.g.
template.ExecuteTemplate(w, "a/home.html", nil)
回答3:
if it is not deeply nested (if you know names of sub-directories beforehand) you can just do this:
t := template.Must(template.ParseGlob("template/*.tmpl"))
template.Must(t.ParseGlob("template/layout/*.tmpl"))
Then for each sub-directory do the same as for 'layout'
回答4:
You can load multiple subdirectories this way. Here we ignore if subdirectories do not exist. But we want to make sure that the first directory can be loaded.
func ParseTemplates() (*template.Template, error) {
templateBuilder := template.New("")
if t, _ := templateBuilder.ParseGlob("/*/*/*/*/*.tmpl"); t != nil {
templateBuilder = t
}
if t, _ := templateBuilder.ParseGlob("/*/*/*/*.tmpl"); t != nil {
templateBuilder = t
}
if t, _ := templateBuilder.ParseGlob("/*/*/*.tmpl"); t != nil {
templateBuilder = t
}
if t, _ := templateBuilder.ParseGlob("/*/*.tmpl"); t != nil {
templateBuilder = t
}
return templateBuilder.ParseGlob("/*.tmpl")
}
回答5:
I made a package that solves exactly this problem.
https://github.com/karelbilek/template-parse-recursive
package main
import (
"html/template"
"os"
recurparse "github.com/karelbilek/template-parse-recursive"
)
func main() {
t, err := recurparse.HTMLParse(
template.New("templates"),
"path/to/templates",
"*.html",
)
if err != nil {
panic(err)
}
templateUnder := t.Lookup("subdir/subdir/template.html")
templateUnder.Execute(os.Stdout, nil)
}
来源:https://stackoverflow.com/questions/38686583/golang-parse-all-templates-in-directory-and-subdirectories