Перейти template.ExecuteTemplate включает html
Я следовал этому руководству: http://golang.org/doc/articles/wiki/final.go и немного изменил его для моих потребностей/желаний. Проблема в том, что я хочу поддерживать HTML в шаблонах. Я понимаю, что это риск для безопасности, но это не проблема на данный момент.
Результат рендеринга страницы:
<h1>this<strong>is</strong>a test</h1>
Позвольте мне немного пояснить код:
type Page struct {
Title string
Body []byte
}
Данные, которые я хотел бы иметь HTML, хранятся в Page.Body
. Это тип []byte
, который означает, что я не могу (или могу?) Запустить html/template.HTML(Page.Body)
, поскольку эта функция ожидает строку.
У меня есть это, которое предварительно отображает шаблоны:
var (
templates = template.Must(template.ParseFiles("tmpl/edit.html", "tmpl/view.html"))
)
И фактическое ExecuteTemplate
выглядит так:
err := templates.ExecuteTemplate(w, tmpl+".html", p)
Где w w http.ResponseWriter
, tmpl tmpl string
, а p - p *Page
Наконец, мой 'view.html'
(шаблон) выглядит следующим образом:
<h1>{{.Title}}</h1>
<p>[<a href="/edit/{{.Title}}">edit</a>]</p>
<div>{{printf "%s" .Body}}</div>
Что я пробовал:
-
{{printf "%s" .Body | html}}
ничего не делает
- Я включил
github.com/russross/blackfriday
(процессор Markdown) и запустил p.Body = blackfriday.MarkdownCommon(p.Body)
, который корректно преобразует Markdown в HTML, но HTML все равно выводится как объекты.
-
EDIT: Я попытался выполнить следующий бит кода (я не знаю, почему формат испорчен), и он все равно выводит то же самое.
var s template.HTML
s = template.HTML(p.Body)
p.Body = []byte(s)
Любые рекомендации приветствуются. Если я запутаюсь, спросите меня, и я могу изменить свой вопрос.
Ответы
Ответ 1
Преобразуйте []byte
или string
, чтобы напечатать template.HTML
(зарегистрированный здесь)
p.Body = template.HTML(s) // where s is a string or []byte
Затем в вашем шаблоне просто:
{{.Body}}
Он будет напечатан без экранирования.
ИЗМЕНИТЬ
Чтобы иметь возможность включать HTML в тело страницы, вам нужно изменить объявление типа Page
:
type Page struct {
Title string
Body template.HTML
}
затем назначьте его.
Ответ 2
Взгляните на template.HTML. Его можно использовать для инкапсуляции известного безопасного фрагмента HTML (например, выход из Markdown). Пакет "html/template" не сможет избежать этого типа.
type Page struct {
Title string
Body template.HTML
}
page := &Page{
Title: "Example",
Body: template.HTML(blackfriday.MarkdownCommon([]byte("foo bar")),
}
Обычно я пишу свой собственный метод func Markdown(text string) html.Template
, который вызывает blackfriday с соответствующей конфигурацией и делает некоторые преобразования типов. Другой альтернативой может быть также регистрация функции "html" в парсере шаблонов, которая позволяет выводить любое значение без какого-либо выхода, делая что-то вроде {{html .MySafeStr}}
. Код может выглядеть так:
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
Я создал пользовательскую функцию для шаблона следующим образом:
func noescape(str string) template.HTML {
return template.HTML(str)
}
var fn = template.FuncMap{
"noescape": noescape,
}
Затем на вашем шаблоне:
{{ noescape $x.Body }}
Ответ 4
Я использую Beego и React.js и часами пытаюсь запустить парсер JSX. Оказывается, html/template выделяет комментарии, особенно блок js doc/** @jsx React.DOM */.
Обходите его, создавая специальный метод для ввода комментария как JS и вызова его из шаблона.
// 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
Вот подход, который не требует каких-либо изменений в ваших существующих структурах и очень минимальное добавление к вашим шаблонам:
Измените эти строки:
var (
templates = template.Must(template.ParseFiles("tmpl/edit.html", "tmpl/view.html"))
)
к этому (включите funcmap с функцией, которая выведет неэкранированный 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"))
А потом просто измените свой HTML-код шаблона следующим образом:
<div>{{printf "%s" .Body}}</div>
к этому (используйте свою новую функцию):
<div>{{ .Body | safeHTML }}</div>
Намного проще!
Ответ 6
Для уточнения и более простого способа передачи HTML в шаблон см.
https://groups.google.com/forum/#!topic/golang-nuts/8L4eDkr5Q84
Просто создайте свою строку HTML через go и передайте ее в свой шаблон, например:
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
Почему бы не преобразовать []byte
в строку? Вы можете сделать это следующим образом:
str := string(page.Body)