dozr13344 2014-01-29 14: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 15: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.

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

报告相同问题?

悬赏问题

  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料