Go Template Nesting Best practices

Source: Internet
Author: User
Tags glob
This is a creation in Article, where the information may have evolved or changed.

The Go official library offers two template libraries: Text/template and Html/template. The two libraries are similar, except that the html/template HTML format has been specially processed, which needs to be used when outputting HTML-formatted code html/template .

Using templates can help us write some common code, or provide a clear file layout, or provide a code generator.

The official documentation provides a good way to use the template, which text/template provides the basics of how to use the template, such as Action, Argument, Pipeline, Variable, Function, template nesting introduction, the html/template Context is introduced. This article assumes that you already understand these basics. If you are not sure, or have not used the template, you can refer to the reference document at the end of the study.

Although the text/template official documentation on template nesting is simple to introduce, but for the use of nested templates for the actual development, as well as considerations are not described in detail, so this article focuses on the use of nested templates.

Although this article is named as a best practice for nested templates, it's just one of the best practices, to be precise. If the reader has other practical scenarios, or better deal with the template nesting scenarios, welcome to discuss.

When we develop a Web application, it is unavoidable to use the template.

Generally a site contains a lot of pages, such as news pages, registration pages, the list of articles and so on. Different news may use the same news layout template, different article detail page may also use the same article layout page, while the News layout template and Article layout page may also have some common things, such as header, footer, navigation bar and so on. How to extract these common things into a unified template?

This article will step through these techniques and first describe the use of nested files.

Parse vs Parsefiles vs Parseblob

Let's start by looking at how the three files are different. In fact, there are five of files:

12345
func Parsefiles (Filenames ... string) (*template, error) func string) (*template, error) func string) (*template, error) func (t *template) Parsefiles (Filenames ... string) (*template, error) func string) (*template, error)

ParseUsed to parse a string that represents the content of the template, and the nested template is associated with the template.

123
Tmpl, err: = template. New ("name"). Parse (...) //Error checking elidederr = Tmpl. Execute (out, data)

And

1234
Import "Html/template"... t, err: = template. New ("foo"). Parse (' \{\{define ' t "\}\}hello, \{\{.\}\}!\{\{end\}\} '" T ""<script>alert (' You have Been Pwned ') </script> ")

ParseFilesUsed to parse a named set of file templates, when the template is defined in different files, using this method can produce an executable template, the template will be executed without error.
ParseGlobParseFilessimilar to this, it uses filepath.Glob pattern matching to traverse files and generate templates for these files.

These two functions can also be *Template used as methods. When used as a function, it returns the name of the template as the name of the first file, the template with the first file as the base template.
At the same time, the subsequent files will also generate templates as the template of the association, you can find it through the Lookup method, because each template is saved its associated version:

1
Map [string]*template

Let's illustrate the use of nested templates with an example.

There are two files under the current folder.
Header.html

12
"Footer"\}\}

Footer.html

1
"Footer"\}\}body is \{\{. Body\}\}\{\{end\}\}

Test procedure:

12345678910111213141516171819202122
 package  mainimport  (  "html/template"   "net/http" ) func  handler (w http. Responsewriter, R *http. Request) {T, _: = template. Parsefiles ( "header.html" , ) Err: = T.execute ( W, map  [string ]string  { Span class= "string" "Title" :  "My Title" ,  "Body" : Span class= "string" > "Hi This is my Body" }) if  err! = nil  {panic  (Err)}}func  main () {http. Handlefunc (, Handler) http. Listenandserve (, nil )} 

Browser access http://localhost:8080/ will result in rendering:

12
Title is My titlebody is

You can see that the results are basically in line with expectations. Nested header.html footer templates, rendering when the header.html main template display, nested rendering footer.html .

But the above results show a little bit of a problem, that is, the footer rendering time does not show the body results, this is because the data is passed to the main template, nested template if you want to use this information, you need to be in a nested place to pass data to it. We can modify header.html :

12
Title is \{\{. Title\}\}\{\{template "Footer" <div class= "" ></div>\}\}

This footer.html allows you to render using the incoming data:

12
 is  is  This  is Body

In the use ParseFiles , ParseGlob function , the default is the path of the last part of the file as the template name, such as the template name of the file, a/foo foo but if the parameters in different folders under the same name, the last template file with the same name will " Overwrite "The previous duplicate file template, the official library implementation cannot save the duplicate template file."

Execute vs Executetemplate

The example above shows the use of a simple nested template, but if we exchange the order of two files, as follows:

12345678
func Handler (w http. Responsewriter, R *http. Request) {T, _: = template. Parsefiles ("footer.html""header.html"map[string]string{"Title "my title" "Body""Hi This is My Body"})ifnil {panic (ERR)}}

After running the browser access, you will find no error, but also did not render anything.
This is because ' template '. Parsefiles ' Returns the template to the first master template. footer.htmlthere is nothing to render in this case.

In this case, we will need to display a template that specifies the rendering to be rendered:

 123456789 
 func  handler (w http. Responsewriter, R *http. Request) {T, _: = template. Parsefiles ( "footer.html" , ) //err: = T.execute (W, map[string]string{"title": "My title", "Body": "Hi this is My Body"})  E RR: = T.executetemplate (W, , map  [string ]string  {:  "My title" , :  "Hi this is My Body" }) if  err! = nil  {panic  (Err)}} 

Use ExecuteTemplate a template that can choose to render t the association as the main template for rendering. In the example above we chose header.html to be the main template, so it renders normally.

Or, the following method can be rendered normally, and it is basically equivalent to the above code (only the small difference of escape).

 123456789 
 func  handler (w http. Responsewriter, R *http. Request) {T, _: = template. Parsefiles ( "footer.html" , ) T = t.lookup ( Span class= "string" > "header.html" ) Err: = T.execute (W, map  [ string ] string  {:  "My Title" ,  "Body" :  "Hi This is my Body" }) //err: = T.executetemplate (W, "header.html", map[string]string{"title": "My title", "Body": "Hi This is my Body "}"  if  err! = nil  {panic  (Err)}} 

So you can see the Execute ExecuteTemplate difference between the features and when you want to render with the specified associated template, use it ExecuteTemplate .

Best practices

With the foundation above, we can solve the problem that the article starts with: How to plan a template for a website?

Suppose there are three files:,, hello.html header.html footer.html which hello.html is the unified layout of a column, header.html is the header of all the layout needs to be nested HTML, such as site description, CSS, navigation bar, including the footer.html introduction of global JavaScript files , copyright notices, and so on.

We created two folders:,, put in a layouts widgets folder, put it in a hello.html layouts header.html footer.html widgets folder,
Let's take these three files as an example to see how nested templates are used in Web sites.

But before I do this, I need to introduce a problem in the code above. As you can see, each of the above requests will read the template file and parse it, which can seriously affect the performance of the program, the solution is to pre-read these files and generate template objects, so that the request is directly using the parsed template object.

12345678910111213141516171819202122232425
varTemplatesMap[string]*template. TemplatefuncInit () {ifTemplates = =Nil{templates = Make(Map[string]*template. Template)}//templatesdir: = "./templates/"TemplatesDir: ="./"layouts, err: = FilePath. Glob (TemplatesDir +"Layouts/*.html")ifErr! =Nil{log. Fatal (Err)}widgets, err: = FilePath. Glob (TemplatesDir +"Widgets/*.html")ifErr! =Nil{log. Fatal (ERR)} for_, Layout: =Rangelayouts {files: =Append(Widgets, layout) Templates[filepath. Base (layout)] = template. Must (template. Parsefiles (Files ...)}}

With an map object, we save the template object for each layout.

Then provide a way to render the template:

123456789
func string Interface {}) Error {Tmpl, OK: = Templates[name]if !ok {return FMT. Errorf ("The template%s does not exist.", name)}w.header (). Set ("Content-type" "text/html; Charset=utf-8 ")return Tmpl. Executetemplate (w, name, data)}

I used this method when developing the Web GUI for rpcx: Rpcx-ui.

Of course, through some transformations can also achieve other template design, such as a base.html template, which defines the header,footer, but also nested body template, through the different body template to achieve different template layout, such as the definition of the news.html body to display news, music.htmldefines the body of music, which is also a good template layout.

Reference documents

    1. https://golang.org/pkg/text/template/
    2. https://golang.org/pkg/html/template/
    3. https://elithrar.github.io/article/approximating-html-template-inheritance/
    4. Https://groups.google.com/forum/#!topic/golang-nuts/EweRbwa_tks
    5. Http://stackoverflow.com/questions/12224436/multiple-files-using-template-parsefiles-in-golang
    6. https://gohugo.io/templates/go-templates/
    7. Https://astaxie.gitbooks.io/build-web-application-with-golang/content/en/07.4.html
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.