英文:
In Go templates, I can get Parse to work but cannot get ParseFiles to work in like manner. Why?
问题
我有以下代码:
t, err := template.New("template").Funcs(funcMap).Parse("Howdy {{ myfunc . }}")
在这种形式下一切都正常工作。但是,如果我使用ParseFiles做完全相同的事情,将上面的文本放在template.html
中,就不行了:
t, err := template.New("template").Funcs(funcMap).ParseFiles("template.html")
我能够以以下形式使ParseFiles工作,但无法使Funcs生效:
t, err := template.ParseFiles("template.html")
t.Funcs(funcMap)
当然,这最后一种形式是直接调用函数而不是调用接收器方法,所以不是同一件事。
有人知道这里发生了什么吗?在网络上很难找到关于模板的详细信息。
英文:
I have the following code:
t, err := template.New("template").Funcs(funcMap).Parse("Howdy {{ myfunc . }}")
In this form everything works fine. But if I do exactly the same thing with ParseFiles, placing the text above in template.html
it's a no go:
t, err := template.New("template").Funcs(funcMap).ParseFiles("template.html")
I was able to get ParseFiles to work in the following form, but cannot get Funcs to take effect:
t, err := template.ParseFiles("template.html")
t.Funcs(funcMap)
Of course, this last form is a direct call to a function instead of a call to the receiver method, so not the same thing.
Any one have any ideas what's going on here? Difficult to find a lot of detail on templates out in the either.
答案1
得分: 3
在源代码中找到了关于template.ParseFiles
的注释:
> 如果第一个模板还没有定义,它将成为返回值,并且我们将使用它来关联所有后续的New调用。此外,如果该文件与t具有相同的名称,则该文件将成为t的内容,因此t, err := New(name).Funcs(xxx).ParseFiles(name)可以工作。否则,我们将创建一个与t关联的新模板。
因此,给定我上面的示例,格式应该如下:
t, err := template.New("template.html").Funcs(funcMap).ParseFiles("path/template.html")
.New("template.html")
创建一个具有给定名称的空模板,.Funcs(funcMap)
关联我们想要应用于模板的任何自定义函数,然后 .ParseFiles("path/template.html")
解析一个或多个模板,并与这些函数关联起来,并将内容与具有该名称的模板关联起来。
请注意,第一个文件的基本名称必须与New
中使用的名称相同。解析的任何内容都将与具有与系列中第一个文件相同的基本名称的空预定义模板或具有该基本名称的新模板关联。
因此,在我上面的示例中,创建了一个名为"template"的空模板,并与一个函数映射关联。然后创建了一个名为"template.html"的新模板。**它们不是同一个模板!**由于最后调用了ParseFiles
,所以t
最终成为"template.html"模板,没有任何附加的函数。
那最后一个示例怎么样?为什么它不起作用?template.ParseFiles 调用了接收器方法 Parse,该方法会应用之前注册的任何函数:
trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
这意味着在解析之前必须先注册自定义函数。在解析模板后添加函数没有任何影响,导致在运行时尝试调用自定义函数时出现空指针错误。
所以我认为这回答了我的原始问题。这里的设计似乎有点笨拙。如果链式调用ParseFiles
到一个模板,并且它们恰好没有相同的名称,最终返回的模板将与链式调用的模板不同。这是不直观的,可能应该在未来的版本中解决,以避免混淆。
英文:
Did some digging and found this comment for template.ParseFiles
in the source:
> First template becomes return value if not already defined, and we use that one for subsequent New calls to associate all the templates together. Also, if this file has the same name as t, this file becomes the contents of t, so t, err := New(name).Funcs(xxx).ParseFiles(name) works. Otherwise we create a new template associated with t.
So the format should be as follows, given my example above:
t, err := template.New("template.html").Funcs(funcMap).ParseFiles("path/template.html")
.New("template.html")
creates an empty template with the given name, .Funcs(funcMap)
associates any custom functions we want to apply to our templates, and then .ParseFiles("path/template.html")
parses one or more templates with an awareness of those functions and associates the contents with a template of that name.
Note that the base name of the first file MUST be the same as the name used in New
. Any content parsed will be associated with either an empty preexisting template having the same base name of the first file in the series or with a new template having that base name.
So in my example above, one empty template named "template" was created and had a function map associated with it. Then a new template named "template.html" was created. THESE ARE NOT THE SAME! And since, ParseFiles
was called last, t
ends up being the "template.html" template, without any functions attached.
What about the last example? Why didn't this work? template.ParseFiles calls the receiver method Parse, which in turn applies any previously registered functions:
trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
This means that custom functions have to be registered prior to parsing. Adding the functions after parsing the templates doesn't have any affect, leading to nil pointer errors at runtime when attempting to call a custom function.
So I think that covers my original question. The design here seems a little clunky. Doesn't make sense that I can chain on ParseFiles
to one template and end up returning a different template from the one I am chaining from if they don't happen to be named the same. That is counterintuitive and probably ought to be addressed in future releases to avoid confusion.
答案2
得分: 0
ParseFiles
应该有一些模板的名称,这些名称是文件名的基本名称。但是你调用了template.New
,它创建了一个名为error
的新模板。所以你应该选择其中一个模板。
foo.go
package main
import (
"text/template"
"log"
"os"
"strings"
)
func main() {
tmpl, err := template.New("error").Funcs(template.FuncMap{
"trim": strings.TrimSpace,
}).ParseFiles("foo.tmpl")
if err != nil {
log.Fatal(err)
}
tmpl = tmpl.Lookup("foo.tmpl")
err = tmpl.Execute(os.Stdout, " string contains spaces both ")
if err != nil {
log.Fatal(err)
}
}
foo.tmpl
{{. | trim}}
英文:
ParseFiles
should have some names of templates which is basename of filename. But you call template.New
, it's create new one of template named error
. So you should select one of templates.
foo.go
package main
import (
"text/template"
"log"
"os"
"strings"
)
func main() {
tmpl, err := template.New("error").Funcs(template.FuncMap{
"trim": strings.TrimSpace,
}).ParseFiles("foo.tmpl")
if err != nil {
log.Fatal(err)
}
tmpl = tmpl.Lookup("foo.tmpl")
err = tmpl.Execute(os.Stdout, " string contains spaces both ")
if err != nil {
log.Fatal(err)
}
}
foo.tmpl
{{. | trim}}
答案3
得分: 0
请尝试这样写:
var templates = template.Must(template.New("").Funcs(fmap).ParseFiles("1.tmpl", "2.tmpl"))
英文:
try this:
var templates = template.Must(template.New("").Funcs(fmap).ParseFiles("1.tmpl, "2.tmpl"))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论