这是我的目录结构:
app/
template/
layout/
base.tmpl
index.tmpl
template.ParseGlob("*/*.tmpl")
在index.tmpl
子目录中解析base.tmpl
但不解析layout
。有没有办法递归地解析所有模板?
答案 0 :(得分:11)
我没有实现你自己的功能,我一直在使用这样的东西
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
}
这将解析您的所有模板,然后您可以通过调用它们的名称来渲染它们,例如
template.ExecuteTemplate(w, "home", nil)
答案 1 :(得分:3)
Datsik的答案有一个缺点,即当多个目录包含许多模板时会出现名称冲突问题。如果不同目录中的两个模板具有相同的文件名,则它将无法正常工作:只有第二个模板可用。
这是由template.ParseFiles的实现引起的,所以我们可以通过避免template.ParseFiles来解决它。这是一个改进的步行算法,它做到了这一点;它直接使用template.Parse。
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)
t, e2 = t.Parse(string(b))
if e2 != nil {
return e2
}
}
return nil
})
return root, err
}
这将解析您的所有模板,然后您可以通过调用它们的名称来渲染它们,例如
template.ExecuteTemplate(w, "a/home.html", nil)
答案 2 :(得分:0)
如果它不是深度嵌套的(如果您事先知道子目录的名称),则可以这样做:
t := template.Must(template.ParseGlob("template/*.tmpl"))
template.Must(t.ParseGlob("template/layout/*.tmpl"))
然后每个子目录与“布局”相同
答案 3 :(得分:0)
您可以通过这种方式加载多个子目录。在这里,我们忽略子目录是否不存在。但是我们要确保可以加载第一个目录。
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")
}
答案 4 :(得分:0)
我制作了一个包来解决这个问题。
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)
}
答案 5 :(得分:0)
有了 pete911 的回答,我可以创建这个函数来解析多个子目录中的所有 html 模板。
// parse.go
func ParseHtmlTemplates() *template.Template {
var directories []string
var filenames []string
// Root directory of template files
root := "./templates"
// Get all directories on /templates and check if there's repeated files
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
// Is file
filename := info.Name()
hasRepeatedFiles := contains(filenames, filename)
if hasRepeatedFiles {
return fmt.Errorf("You can't have repeated template files: %s", filename)
}
filenames = append(filenames, filename)
} else {
// Is directory
directories = append(directories, path)
}
return nil
})
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Create a template for parsing all directories
tmpl := template.Must(template.ParseGlob(root + "/*.html"))
// Parse all directories (minus the root directory)
for _, path := range directories[1:] {
pattern := path + "/*.html"
template.Must(tmpl.ParseGlob(pattern))
}
return tmpl
}
// contains private method
func contains(filenames []string, filename string) bool {
for _, f := range filenames {
if f == filename {
return true
}
}
return false
}
// main.go
func main() {
tmpl = ParseHtmlTemplates()
if err := tmpl.Execute(os.Stdout, ""); err != nil {
panic(err)
}
}