dozr13344 2014-01-29 06:25
浏览 77
已采纳

将模板直接渲染成HTML

I've recently swapped out datastores and as a side-effect have had to change a struct field from template.HTML to string to be compatible with the marshaller/DB driver. This field, RenderedDesc, contains rendered HTML as passed through russross/blackfriday.

Previously I could just pass the whole struct into the template "as is" and call {{ .RenderedDesc }} in the template.

Because it's now a string, I've added a filter to convert it back on template render:

templates.go

func RenderUnsafe(s string) template.HTML {
    return template.HTML(s)
}

template.FuncMap{
        ...
        "unsafe": RenderUnsafe,
    }

_content.tmpl

...
<div class="detail">

    {{ .RenderedDesc | unsafe }}

</div>
...

Is there a better way to achieve this without having to use a filter at the template level? Short of re-writing marshalling logic from my DB driver (not on the cards) it looks like this is the simplest way to "store" strings but render raw HTML.

  • 写回答

1条回答 默认 最新

  • duankousong9637 2014-01-29 07:44
    关注

    IMHO, the right way to do this is using a filter, like you are already doing. There are more ways to achieve the same, one of them is using tags and converting the struct in to a map[string]Interface{}. Because map fields can be reached in the same way that structs, your templates will remain unmodified.

    Show me the code (playground):

    package main
    
    import (
        "html/template"
        "os"
        "reflect"
    )
    
    var templates = template.Must(template.New("tmp").Parse(`
        <html>
            <head>
            </head>
            <body>
                <h1>Hello</h1>
                <div class="content">
                    Usafe Content = {{.Content}}
                    Safe Content  = {{.Safe}}
                    Bool          = {{.Bool}}
                    Num           = {{.Num}}
                    Nested.Num    = {{.Nested.Num}}
                    Nested.Bool   = {{.Nested.Bool}}
                </div>
            </body>
        </html>
    `))
    
    func asUnsafeMap(any interface{}) map[string]interface{} {
        v := reflect.ValueOf(any)
        if v.Kind() != reflect.Struct {
            panic("asUnsafeMap invoked with a non struct parameter")
        }
        m := map[string]interface{}{}
        for i := 0; i < v.NumField(); i++ {
            value := v.Field(i)
            if !value.CanInterface() {
                continue
            }
            ftype := v.Type().Field(i)
            if ftype.Tag.Get("unsafe") == "html" {
                m[ftype.Name] = template.HTML(value.String())
            } else {
                m[ftype.Name] = value.Interface()
            }
        }
        return m
    }
    
    func main() {
        templates.ExecuteTemplate(os.Stdout, "tmp", asUnsafeMap(struct {
            Content string `unsafe:"html"`
            Safe    string
            Bool    bool
            Num     int
            Nested  struct {
                Num  int
                Bool bool
            }
        }{
            Content: "<h2>Lol</h2>",
            Safe:    "<h2>Lol</h2>",
            Bool:    true,
            Num:     10,
            Nested: struct {
                Num  int
                Bool bool
            }{
                Num:  9,
                Bool: true,
            },
        }))
    }
    

    Output:

    <html>
        <head>
        </head>
        <body>
            <h1>Hello</h1>
            <div class="content">
                Usafe Content = <h2>Lol</h2>
                Safe Content  = &lt;h2&gt;Lol&lt;/h2&gt;
                Bool          = true
                Num           = 10
                Nested.Num    = 9
                Nested.Bool   = true
            </div>
        </body>
    </html>
    

    Note: the previous code doesn't work with nested structures, but it will be easy to add support for them. Also, every field tagged as unsafe will be treated as string.

    展开全部

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
编辑
预览

报告相同问题?

手机看
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回
顶部