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 怎么生成确定数目的泊松点过程
  • ¥15 python点云生成mesh精度不够怎么办
  • ¥15 QT C++ 鼠标键盘通信
  • ¥15 改进Yolov8时添加的注意力模块在task.py里检测不到
  • ¥50 高维数据处理方法求指导
  • ¥100 数字取证课程 关于FAT文件系统的操作
  • ¥15 如何使用js实现打印时每页设置统一的标题
  • ¥15 安装TIA PortalV15.1报错
  • ¥15 能把水桶搬到饮水机的机械设计
  • ¥15 Android Studio中如何把H5逻辑放在Assets 文件夹中以实现将h5代码打包为apk