2

I am trying to change the default delimiters for Golang hml templates and here is the code I am using now:

func indexHandler(w http.ResponseWriter, r *http.Request) {
  pageFile := "html/testpage.html"
  tmpl, err := template.New(pageFile).Delims("[[", "]]").ParseFiles(pageFile)
  //tmpl := template.Must(template.ParseFiles(pageFile))
  if (err!=nil){
    fmt.Println("Error")
    fmt.Println(err)
  }

  tmpl.Execute(w, nil)
}

The above code renders a blank page in the browser. It will render properly if I use the commented out code instead of the second line.

Here is the template page source:

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">

  <title>The HTML5 </title>
  <meta name="description" content="HTML5">
  <meta name="author" content="Test">   
</head>    
<body>
  This is html page
</body>
</html>

My go version is: go version go1.10.2 linux/amd64

I run it by go run test.go test.go being in the main package

There is no error message being printed in the browser or the terminal.

What am I missing here?

Devasia Joseph
  • 388
  • 4
  • 14

3 Answers3

4

After some research and discussions i guess this line is ill formed:

tmpl, err := template.New(pageFile).ParseFiles(pageFile)

You don't need to do a New(pageFile). You only need to use the ParseFiles method directly and bear in mind that the name of the templaes will be equals to the base names of the passed files.

So, touch a little bit yhe code and use:

tmpl, err := template.ParseFiles(pageFile)

See this example for more

Victor
  • 3,841
  • 2
  • 37
  • 63
3

Since html/template uses text/template underneath, you can often find additional information regarding how templates work in the text/template package.

From the docs of ParseFiles:

Since the templates created by ParseFiles are named by the base names of the argument files, t should usually have the name of one of the (base) names of the files. If it does not, depending on t's contents before calling ParseFiles, t.Execute may fail. In that case use t.ExecuteTemplate to execute a valid template.

(emphasis mine)


The problem is caused by the fact that you are passing the template file's path as the name of the template and then calling the ParseFiles method.

Because of how ParseFiles, and ParseGlob for that matter, are implemented, this causes an inconsistency between the name you explicitly passed to New and the names these two methods assign to the parsed templates.

You can test this by calling the DefinedTemplates method.

https://play.golang.org/p/LEi-xSn4LOF


Also please take a look at @icza's Go template name answer to get a better understanding of templates.

mkopriva
  • 35,176
  • 4
  • 57
  • 71
  • finally I could reproduce the OP problem, please see; https://play.golang.org/p/DOBzNqEdBjc – Victor May 16 '18 at 21:12
  • my example "doesn't work", it shows that when you use the path as the name and then call ParseFiles you'll get an inconsistency between the name of the template `t` and the name of the actual parsed template. `path+ParseFiles => name is: /tmp/054003078 ; defined templates are: "054003078"` this is not an ok output. – mkopriva May 16 '18 at 21:16
  • your example was incomplete... i just complete it in order to get the OP error... thanks ;) – Victor May 16 '18 at 21:17
  • consider adding the example that actually PRINTS an error, just a suggestion.. it helps me. – Victor May 16 '18 at 21:20
  • If all you want is to reproduce that specific error you can do this: `template.New("whatever").Execute(os.Stdout, nil)`. – mkopriva May 16 '18 at 21:23
  • not that @mkproiva i guess you are not getting into what i'm trying to find is the *root* of the problem. If you refer to the file using a path that includes "/" for the name of the template you get the problem. Instead if you only use the base name you won't, because there is no "/" in the path. – Victor May 16 '18 at 21:53
  • what happens if the use employs pageFile := "testpage.html", that would work? (assuming that the file is at that location at runtime) – Victor May 16 '18 at 21:56
  • That would work because the filepath and base name are the same. But passing "tmp/testpage.html" (without the leading "/") is not the base name of the file and therefore **may** fail. – mkopriva May 16 '18 at 21:58
  • so please, try to bear with me and don't deny that "/" is part of the problem. – Victor May 16 '18 at 21:59
  • you have said that... if you employ an "/" you get the problem, if you don't employ you don't... so.. i'm not saying THAT is the problem... i'm saying that is important part of the problem. – Victor May 16 '18 at 22:02
  • How is it part of the problem? If "tmp/testpage.html" and "/tmp/testpage.thml" both fail equally, how is "/" the problem here? Please elaborate @VIctor. – mkopriva May 16 '18 at 22:02
  • our discussion would be nice to have with a coffe dear mkpriva. I have plenty of stuff to learn for today. LEt's continue this another day, shall we? – Victor May 16 '18 at 22:03
  • To be clear "/" is not important, it is actually irrelevant, and you should not focus on that. You should think about the cause of the problem in terms of filepaths and base names. – mkopriva May 16 '18 at 22:05
  • well for a start i would argue that using template.NEw() followed by template.ParseFiles() does have any meaning? why not use directly template.ParseFiles()? I guess that open the way to discussion like the one we are having. See the snippet https://play.golang.org/p/408hyExUQ9k – Victor May 16 '18 at 22:08
  • and yes mkvpriva, by using "/" you are introducing an error to the ill way of using template. Ill way = `Template.NEw("blabla").ParseFiles(files)` – Victor May 16 '18 at 22:09
  • coffe with sugar? – Victor May 16 '18 at 22:10
0
func indexHandler(w http.ResponseWriter, r *http.Request) {
  pageFile := "html/testpage.html"
  name := "testpage"
  tmpl, err := template.New(name).Delims("[[", "]]").ParseFiles(pageFile)  //only translate a "name" to New()
  //tmpl := template.Must(template.ParseFiles(pageFile))
  if (err!=nil){
    fmt.Println("Error")
    fmt.Println(err)
  }

  tmpl.Execute(w, nil)
  //tmpl.ExecuteTemplate(w, name, nil)
}