问题
I have followed this tutorial: http://golang.org/doc/articles/wiki/final.go and have slightly modified it for my needs/wants. The problem is I would like to support HTML in the templates. I realize this is a security risk but it's not a concern at the moment.
The result of a page render:
<h1>this<strong>is</strong>a test</h1>
Let me explain a little bit of the code:
type Page struct {
Title string
Body []byte
}
The data I would like to have HTML is stored in Page.Body
. This is type []byte
which means I can't (or can I?) run html/template.HTML(Page.Body)
as that function expects a string.
I have this which pre-renders the templates:
var (
templates = template.Must(template.ParseFiles("tmpl/edit.html", "tmpl/view.html"))
)
And the actual ExecuteTemplate
looks like this:
err := templates.ExecuteTemplate(w, tmpl+".html", p)
Where w is w http.ResponseWriter
, tmpl is tmpl string
, and p is p *Page
Finally my 'view.html'
(template) looks like the following:
<h1>{{.Title}}</h1>
<p>[<a href="/edit/{{.Title}}">edit</a>]</p>
<div>{{printf "%s" .Body}}</div>
Things I have tried:
{{printf "%s" .Body | html}}
doesn't do anything- I have included
github.com/russross/blackfriday
(Markdown processor) and have runp.Body = blackfriday.MarkdownCommon(p.Body)
which correctly converts Markdown to HTML, but the HTML is still output as entities. EDIT: I have attempted the following bit of code (I don't know why the format is messed up) and it still outputs the exact same.
var s template.HTML
s = template.HTML(p.Body)
p.Body = []byte(s)
Any guidance is greatly appreciated. If I'm being confusing please ask and I can modify my question.
回答1:
Convert your []byte
or string
to type template.HTML
(documented here)
p.Body = template.HTML(s) // where s is a string or []byte
Then, in your template, just:
{{.Body}}
It will be printed without escaping.
EDIT
In order to be able to include HTML in you page's body you need to change the Page
type declaration:
type Page struct {
Title string
Body template.HTML
}
then assign to it.
回答2:
Take a look at the template.HTML type. It can be used to encapsulate a known safe fragment of HTML (like the output from Markdown). The "html/template" package will not escape this this type.
type Page struct {
Title string
Body template.HTML
}
page := &Page{
Title: "Example",
Body: template.HTML(blackfriday.MarkdownCommon([]byte("foo bar")),
}
I usually write my own func Markdown(text string) html.Template
method that calls blackfriday with the appropriate config and does some type conversions. Another alternative might be also to register a "html" func in the template parser, that allows you to output any value without any escaping by doing something like {{html .MySafeStr}}
. The code might look like:
var tmpl = template.Must(template.New("").Funcs(template.FuncMap{
"html": func(value interface{}) template.HTML {
return template.HTML(fmt.Sprint(value))
},
}).ParseFiles("file1.html", "file2.html"))
回答3:
I created a custom function for the template as follows:
func noescape(str string) template.HTML {
return template.HTML(str)
}
var fn = template.FuncMap{
"noescape": noescape,
}
Then on your template:
{{ noescape $x.Body }}
回答4:
I'm using Beego and React.js and fought for hours trying to get the JSX parser to run. Turns out html/template strips out comments especially the js doc block /** @jsx React.DOM */.
Got around it by creating a special method to Type the comment as JS and calling it from within the template.
// Create a method in your controller (I'm using Beego)
func jsxdoc()(out template.JS) {
return template.JS(`/** @jsx React.DOM */`)
}
// Add method to your function map available to views
beego.AddFuncMap("jsxdoc", jsxdoc)
// In template
<script type="text/jsx">
{{ jsxdoc }}
var CommentBox = React.createClass({
render: function() {
return (
<div class="commentBox">
Hello, world! I am a CommentBox.
</div>
);
}
});
React.renderComponent(
<CommentBox />,
document.getElementById('content')
);
</script>
回答5:
Here's an approach that doesn't require any changes to your existing structs, and a very minimal, additive change to your templates:
Change these lines:
var (
templates = template.Must(template.ParseFiles("tmpl/edit.html", "tmpl/view.html"))
)
to this (include a funcmap with a function that will output un-escaped HTML):
var templates = template.Must(template.New("main").Funcs(template.FuncMap{
"safeHTML": func(b []byte) template.HTML {
return template.HTML(b)
},
}).ParseFiles("tmpl/edit.html", "tmpl/view.html"))
And then just change your template HTML from this:
<div>{{printf "%s" .Body}}</div>
to this (use your new function):
<div>{{ .Body | safeHTML }}</div>
Much easier!
回答6:
For clarification and a much simpler way of passing HTML to template, see
https://groups.google.com/forum/#!topic/golang-nuts/8L4eDkr5Q84
Just create your HTML string via go and pass it into your template, e.g.:
Sout := ""
.
.
Sout += fmt.Sprintf(`<tr><td>%s<td align=center>%.2f<td>%s<td>%s<td>%s<td>%s<td align=center>%d<td align=center>%d
<td align=center>%d`, AccountID, amount, remissiondetails, created, begins, ends,
freePDFs, freeinformants, freeSDQs)
.
.
render(w, "templates/Waivers.html", map[string]interface{}{ "Body":template.HTML(Sout), })
回答7:
In my case (where I am populating a view struct
with a list of Activity
), I had to change the property Message string
to Message template.HTML
. Then, when setting the property value I can call activity.Message = template.HTML("The <b>HTML</b>")
.
回答8:
Why not convert the []byte
to a string? You can do it like this:
str := string(page.Body)
来源:https://stackoverflow.com/questions/18175630/go-template-executetemplate-include-html