在Go语言中的HTML模板

huangapple go评论107阅读模式
英文:

HTML templates in golang

问题

我正在按照这个教程进行操作:golang教程-维基百科,除了“其他任务”部分的最后一点之外,我已经成功完成了所有内容。以下是我对教程的实现:

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"html/template"
	"regexp"
)

type Page struct {
	Title string
	Body []byte
}

func (p *Page) save() error {
	filename := "data/" + p.Title + ".txt"
	return ioutil.WriteFile(filename, p.Body, 0600)
}

func loadPage(title string) (*Page, error) {
	filename := "data/" + title + ".txt"
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return &Page{Title: title, Body: body}, nil
}

func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
	t, _ := template.ParseFiles("template/" + tmpl + ".html")
	t.Execute(w, p)
}

func viewHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/view/"):]
	p, err := loadPage(title)
	if err != nil {
		http.Redirect(w, r, "/edit/" + title, http.StatusFound)
		return
	}
	expr := regexp.MustCompile(`\[.+\]`)
	p.Body = expr.ReplaceAllFunc(p.Body, func (match []byte) []byte {
		return []byte("<a href='/view/" + string(match) + "'>" + string(match) + "</a>")
	})
	renderTemplate(w, "view", p)
}

func saveHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/save/"):]
	body := r.FormValue("body")
	p := &Page{Title: title, Body: []byte(body)}
	p.save()
	http.Redirect(w, r, "/view/" + title, http.StatusFound)
}

func editHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/edit/"):]
	p, err := loadPage(title)
	
	if err != nil {
		p = &Page{Title: title}
	}
	renderTemplate(w, "edit", p)
}

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/view/index", http.StatusFound)	
	})
	http.HandleFunc("/view/", viewHandler)
	http.HandleFunc("/edit/", editHandler)
	http.HandleFunc("/save/", saveHandler)
	http.ListenAndServe(":8080", nil)
	fmt.Println("Running")
}

html/template引擎按预期打印了锚点标签,但是使用HTML实体进行了转义。我还没有找到合适的方法来解决这个问题。

英文:

I'm following this tutorial:
golang tutorial - wiki and I've managed to get everything working except the last point in the "other task" section. My Implementation of the tutorial:

package main
import (
&quot;fmt&quot;
&quot;io/ioutil&quot;
&quot;net/http&quot;
&quot;html/template&quot;
&quot;regexp&quot;
)
type Page struct {
Title string
Body []byte
}
func (p *Page) save() error {
filename := &quot;data/&quot; + p.Title + &quot;.txt&quot;
return ioutil.WriteFile(filename, p.Body, 0600)
}
func loadPage(title string) (*Page, error) {
filename := &quot;data/&quot; + title + &quot;.txt&quot;
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &amp;Page{Title: title, Body: body}, nil
}
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
t, _ := template.ParseFiles(&quot;template/&quot; + tmpl + &quot;.html&quot;);
t.Execute(w, p)
}
func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[len(&quot;/view/&quot;):]
p, err := loadPage(title)
if err != nil {
http.Redirect(w, r, &quot;/edit/&quot; + title, http.StatusFound);
return
}
expr := regexp.MustCompile(`\[.+\]`)
p.Body = expr.ReplaceAllFunc(p.Body, func ( match []byte) []byte {
return []byte(&quot;&lt;a href=&#39;/view/&quot; + string(match) + &quot;&#39;&gt;&quot; + string(match) + &quot;&lt;/a&gt;&quot;)
})
renderTemplate(w, &quot;view&quot;, p);
}
func saveHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[len(&quot;/save/&quot;):]
body := r.FormValue(&quot;body&quot;)
p := &amp;Page{Title: title, Body: []byte(body)}
p.save()
http.Redirect(w, r, &quot;/view/&quot; + title, http.StatusFound)
}
func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[len(&quot;/edit/&quot;):]
p, err := loadPage(title);
if err != nil {
p = &amp;Page{Title: title}
}
renderTemplate(w, &quot;edit&quot;, p);
}
func main() {
http.HandleFunc(&quot;/&quot;, func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, &quot;/view/index&quot;, http.StatusFound)	
})
http.HandleFunc(&quot;/view/&quot;, viewHandler)
http.HandleFunc(&quot;/edit/&quot;, editHandler)
http.HandleFunc(&quot;/save/&quot;, saveHandler)
http.ListenAndServe(&quot;:8080&quot;, nil)
fmt.Println(&quot;Running&quot;);
}

html/template engine prints the anchor tag as expected, but escapes it with html entities. I've not been able to find appropriate way of doing it.

答案1

得分: 5

使用template.HTML将正文标记为安全的HTML。

以下函数将正文转换为HTML。

// 将其移动到包级变量,以便它只编译一次。
var linkPat = regexp.MustCompile(`\[.+\]`)

func toHTML(s string) template.HTML {

  // 首先对字符串中的所有内容进行转义,以确保特殊字符(例如'<')显示为字符,而不是被视为标记。
  s = template.HTMLEscapeString(s)

  // 插入链接。
  s = linkPat.ReplaceAllStringFunc(s, func(m string) string {
    m = m[1 : len(m)-1]
    return "<a href='/view/" + m + "'>" + m + "</a>"
  })

  return template.HTML(s)
}

使用以下方式渲染页面:

renderTemplate(w, "edit", map[string]interface{}{
   "Title": p.Body,
   "Body": toHTML(p.Body),
})
英文:

Use template.HTML to mark the body as safe HTML.

The following function converts the body to HTML.

// Move to package-level variable so that it&#39;s compile once.
var linkPat = regexp.MustCompile(`\[.+\]`)
func toHTML(s string) template.HTML {
// Escape everything in the string first to ensure that
// special characters (&#39;&lt;&#39; for example) are displayed as
// characters and not treated as markup.
s = template.HTMLEscapeString(s)
// Insert the links.
s = linkPat.ReplaceAllStringFunc(s, func(m string) string {
s = s[1 : len(s)-1]
return &quot;&lt;a href=&#39;/view/&quot; + m + &quot;&#39;&gt;&quot; + m + &quot;&lt;/a&gt;&quot;
})
return template.HTML(s)
}

Render the page using:

renderTemplate(w, &quot;edit&quot;, map[string]interface{}{
&quot;Title&quot;: p.Body,
&quot;Body&quot;: toHTML(p.Body),
})

huangapple
  • 本文由 发表于 2014年10月14日 04:50:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/26348659.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定