-<h1>Editing {Title}</h1>
+<h1>Editing {{.Title |html}}</h1>
-<form action="/save/{Title}" method="POST">
-<div><textarea name="body" rows="20" cols="80">{Body|html}</textarea></div>
+<form action="/save/{{.Title |html}}" method="POST">
+<div><textarea name="body" rows="20" cols="80">{{printf "%s" .Body |html}}</textarea></div>
<div><input type="submit" value="Save"></div>
</form>
import (
"http"
"io/ioutil"
- "old/template"
"os"
"regexp"
+ "template"
)
type Page struct {
}
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
- t, err := template.ParseFile(tmpl+".html", nil)
+ t, err := template.ParseFile(tmpl+".html")
if err != nil {
http.Error(w, err.String(), http.StatusInternalServerError)
return
import (
"http"
"io/ioutil"
- "old/template"
"os"
+ "template"
)
type Page struct {
if err != nil {
p = &Page{Title: title}
}
- t, _ := template.ParseFile("edit.html", nil)
+ t, _ := template.ParseFile("edit.html")
t.Execute(w, p)
}
func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
- t, _ := template.ParseFile("view.html", nil)
+ t, _ := template.ParseFile("view.html")
t.Execute(w, p)
}
import (
"http"
"io/ioutil"
- "old/template"
"os"
"regexp"
+ "template"
)
type Page struct {
func init() {
for _, tmpl := range []string{"edit", "view"} {
- templates[tmpl] = template.MustParseFile(tmpl+".html", nil)
+ t := template.Must(template.ParseFile(tmpl+".html"))
+ templates[tmpl] = t
}
}
package main
import (
- "old/template"
+ "template"
"os"
"io/ioutil"
)
func main() {
b, _ := ioutil.ReadAll(os.Stdin)
- template.HTMLFormatter(os.Stdout, "", b)
+ template.HTMLEscape(os.Stdout, b)
}
<ul>
<li>Creating a data structure with load and save methods</li>
<li>Using the <code>http</code> package to build web applications
-<li>Using the <code>old/template</code> package to process HTML templates</li>
+<li>Using the <code>template</code> package to process HTML templates</li>
<li>Using the <code>regexp</code> package to validate user input</li>
<li>Using closures</li>
</ul>
Of course, there is a better way.
</p>
-<h2>The <code>old/template</code> package</h2>
+<h2>The <code>template</code> package</h2>
<p>
-The <code>old/template</code> package is part of the Go standard library.
+The <code>template</code> package is part of the Go standard library.
(A new template package is coming; this code lab will be updated soon.)
We can
-use <code>old/template</code> to keep the HTML in a separate file, allowing
+use <code>template</code> to keep the HTML in a separate file, allowing
us to change the layout of our edit page without modifying the underlying Go
code.
</p>
<p>
-First, we must add <code>old/template</code> to the list of imports:
+First, we must add <code>template</code> to the list of imports:
</p>
<pre>
import (
"http"
"io/ioutil"
- <b>"old/template"</b>
"os"
+ <b>"template"</b>
)
</pre>
</p>
<pre>
-<h1>Editing {Title}</h1>
+<h1>Editing {{.Title |html}}</h1>
-<form action="/save/{Title}" method="POST">
-<div><textarea name="body" rows="20" cols="80">{Body|html}</textarea></div>
+<form action="/save/{{.Title |html}}" method="POST">
+<div><textarea name="body" rows="20" cols="80">{{printf "%s" .Body |html}}</textarea></div>
<div><input type="submit" value="Save"></div>
</form>
</pre>
if err != nil {
p = &Page{Title: title}
}
- t, _ := template.ParseFile("edit.html", nil)
+ t, _ := template.ParseFile("edit.html")
t.Execute(w, p)
}
</pre>
</p>
<p>
-The method <code>t.Execute</code> replaces all occurrences of
-<code>{Title}</code> and <code>{Body}</code> with the values of
-<code>p.Title</code> and <code>p.Body</code>, and writes the resultant
-HTML to the <code>http.ResponseWriter</code>.
+The method <code>t.Execute</code> executes the template, writing the
+generated HTML to the <code>http.ResponseWriter</code>.
+The <code>.Title</code> and <code>.Body</code> dotted identifiers refer to
+<code>p.Title</code> and <code>p.Body</code>.
</p>
<p>
-Note that we've used <code>{Body|html}</code> in the above template.
-The <code>|html</code> part asks the template engine to pass the value
-<code>Body</code> through the <code>html</code> formatter before outputting it,
-which escapes HTML characters (such as replacing <code>></code> with
-<code>&gt;</code>).
-This will prevent user data from corrupting the form HTML.
+Template directives are enclosed in double curly braces.
+The <code>printf "%s" .Body</code> instruction is a function call
+that outputs <code>.Body</code> as a string instead of a stream of bytes,
+the same as a call to <code>fmt.Printf</code>.
+The <code>|html</code> part of each directive pipes the value through the
+<code>html</code> formatter before outputting it, which escapes HTML
+characters (such as replacing <code>></code> with <code>&gt;</code>),
+preventing user data from corrupting the form HTML.
</p>
<p>
</p>
<pre>
-<h1>{Title}</h1>
+<h1>{{.Title |html}}</h1>
-<p>[<a href="/edit/{Title}">edit</a>]</p>
+<p>[<a href="/edit/{{.Title |html}}">edit</a>]</p>
-<div>{Body}</div>
+<div>{{printf "%s" .Body |html}}</div>
</pre>
<p>
func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
- t, _ := template.ParseFile("view.html", nil)
+ t, _ := template.ParseFile("view.html")
t.Execute(w, p)
}
</pre>
<p>
Then we create an <code>init</code> function, which will be called before
<code>main</code> at program initialization. The function
-<code>template.MustParseFile</code> is a convenience wrapper around
-<code>ParseFile</code> that does not return an error code; instead, it panics
-if an error is encountered. A panic is appropriate here; if the templates can't
-be loaded the only sensible thing to do is exit the program.
+<code>template.Must</code> is a convenience wrapper that panics when passed a
+non-nil <code>os.Error</code> value, and otherwise returns the
+<code>*Template</code> unaltered. A panic is appropriate here; if the templates
+can't be loaded the only sensible thing to do is exit the program.
</p>
<pre>
func init() {
for _, tmpl := range []string{"edit", "view"} {
- templates[tmpl] = template.MustParseFile(tmpl+".html", nil)
+ t := template.Must(template.ParseFile(tmpl + ".html"))
+ templates[tmpl] = t
}
}
</pre>
<p>
The function <code>regexp.MustCompile</code> will parse and compile the
regular expression, and return a <code>regexp.Regexp</code>.
-<code>MustCompile</code>, like <code>template.MustParseFile</code>,
-is distinct from <code>Compile</code> in that it will panic if
-the expression compilation fails, while <code>Compile</code> returns an
-<code>os.Error</code> as a second parameter.
+<code>MustCompile</code> is distinct from <code>Compile</code> in that it will
+panic if the expression compilation fails, while <code>Compile</code> returns
+an <code>os.Error</code> as a second parameter.
</p>
<p>
"go/ast"
"go/token"
"log"
- "old/template"
+ "template"
"os"
)
-<h1>{Title}</h1>
+<h1>{{.Title |html}}</h1>
-<p>[<a href="/edit/{Title}">edit</a>]</p>
+<p>[<a href="/edit/{{.Title |html}}">edit</a>]</p>
-<div>{Body}</div>
+<div>{{printf "%s" .Body |html}}</div>
<ul>
<li>Creating a data structure with load and save methods</li>
<li>Using the <code>http</code> package to build web applications
-<li>Using the <code>old/template</code> package to process HTML templates</li>
+<li>Using the <code>template</code> package to process HTML templates</li>
<li>Using the <code>regexp</code> package to validate user input</li>
<li>Using closures</li>
</ul>
Of course, there is a better way.
</p>
-<h2>The <code>old/template</code> package</h2>
+<h2>The <code>template</code> package</h2>
<p>
-The <code>old/template</code> package is part of the Go standard library.
+The <code>template</code> package is part of the Go standard library.
(A new template package is coming; this code lab will be updated soon.)
We can
-use <code>old/template</code> to keep the HTML in a separate file, allowing
+use <code>template</code> to keep the HTML in a separate file, allowing
us to change the layout of our edit page without modifying the underlying Go
code.
</p>
<p>
-First, we must add <code>old/template</code> to the list of imports:
+First, we must add <code>template</code> to the list of imports:
</p>
<pre>
import (
"http"
"io/ioutil"
- <b>"old/template"</b>
"os"
+ <b>"template"</b>
)
</pre>
</p>
<p>
-The method <code>t.Execute</code> replaces all occurrences of
-<code>{Title}</code> and <code>{Body}</code> with the values of
-<code>p.Title</code> and <code>p.Body</code>, and writes the resultant
-HTML to the <code>http.ResponseWriter</code>.
+The method <code>t.Execute</code> executes the template, writing the
+generated HTML to the <code>http.ResponseWriter</code>.
+The <code>.Title</code> and <code>.Body</code> dotted identifiers refer to
+<code>p.Title</code> and <code>p.Body</code>.
</p>
<p>
-Note that we've used <code>{Body|html}</code> in the above template.
-The <code>|html</code> part asks the template engine to pass the value
-<code>Body</code> through the <code>html</code> formatter before outputting it,
-which escapes HTML characters (such as replacing <code>></code> with
-<code>&gt;</code>).
-This will prevent user data from corrupting the form HTML.
+Template directives are enclosed in double curly braces.
+The <code>printf "%s" .Body</code> instruction is a function call
+that outputs <code>.Body</code> as a string instead of a stream of bytes,
+the same as a call to <code>fmt.Printf</code>.
+The <code>|html</code> part of each directive pipes the value through the
+<code>html</code> formatter before outputting it, which escapes HTML
+characters (such as replacing <code>></code> with <code>&gt;</code>),
+preventing user data from corrupting the form HTML.
</p>
<p>
<p>
Then we create an <code>init</code> function, which will be called before
<code>main</code> at program initialization. The function
-<code>template.MustParseFile</code> is a convenience wrapper around
-<code>ParseFile</code> that does not return an error code; instead, it panics
-if an error is encountered. A panic is appropriate here; if the templates can't
-be loaded the only sensible thing to do is exit the program.
+<code>template.Must</code> is a convenience wrapper that panics when passed a
+non-nil <code>os.Error</code> value, and otherwise returns the
+<code>*Template</code> unaltered. A panic is appropriate here; if the templates
+can't be loaded the only sensible thing to do is exit the program.
</p>
<pre>
<p>
The function <code>regexp.MustCompile</code> will parse and compile the
regular expression, and return a <code>regexp.Regexp</code>.
-<code>MustCompile</code>, like <code>template.MustParseFile</code>,
-is distinct from <code>Compile</code> in that it will panic if
-the expression compilation fails, while <code>Compile</code> returns an
-<code>os.Error</code> as a second parameter.
+<code>MustCompile</code> is distinct from <code>Compile</code> in that it will
+panic if the expression compilation fails, while <code>Compile</code> returns
+an <code>os.Error</code> as a second parameter.
</p>
<p>