使用場景: 我們希望在模板里面動態解析指定的模板文件。
這個似乎使用go語言的模板嵌套 template 可以實現,不過模板嵌套聲明里面是不支持使用變量的, 如:{{template "模板文件名" .}}? 這里的"模板文件名"不能使用變量,原因我們另外分析, 所以只能是靜態嵌套其他模板,不能實現動態嵌套其他模板!
golang動態模板解析實現思路
? ? ? ?要實現模板文件的動態解析, 我們可以通過在自定義模板函數的方式來實現。即 這個函數接收一個 模板文件變量 和模板解析參數 然后將模板文件解析為 HTML后返回給調用模板,這樣就實現了模板的動態解析。 【ps: 如果你有更好的思路,歡迎反饋分享 :)】
? ? ? ??
golang HTML動態模板解析實現代碼 示例
import ("bytes""html/template""path/filepath""github.com/spf13/viper" // 配置信息解析,可以使用其他你喜歡的
)// 獲取所有自定義模板函數
func GetFuncs() template.FuncMap {// fmap map[string]anyreturn template.FuncMap{"TplInclude": TplInclude,}
}// 動態模板解析函數 將指定的模板文件渲染為html內容后返回
//
// tplFile 模板文件 這個可以是相對exe所在文件夾的路徑 或者絕對路徑
// datas 可選參數 要應用到模板文件中的數據 通常為map格式
//
// 返回可直接渲染頁面的 template.HTML 格式的字符串
// @author: TekinTian <tekinTian@gmail.com>
// @see https://dev.tekin.cn
func TplInclude(tplFile string, datas ...interface{}) template.HTML {var data interface{} // 應用到模板中的數據,默認空if len(datas) > 0 {data = datas[0] // 從可選參數中獲取}// 從配置文件中獲取分隔符delss := viper.GetStringSlice("viewer.delimiters")if len(delss) != 2 {delss = []string{"", ""} // 使用默認的分隔符,這里留空go最后解析的時候就會使用默認的分隔符 {{ }} 詳情src/text/template/parse/lex.go}// 獲取*template.Template對象 注意如果用到了自定義分隔符,自定義函數,則需要再這里重新注冊t := template.New(tplFile).Delims(delss[0], delss[1]).Funcs(GetFuncs())// 解析模板文件 注意這里的模板文件路徑必須是相對于exe運行文件所在的路徑 或者 絕對路徑tpl, err := t.ParseFiles(filepath.Join("templates", tplFile))if err != nil {return template.HTML(err.Error())}// 新建一個字符串緩存 writer, 解析后的模板內容將寫入到這里// 這里如果是直接輸出到瀏覽器的話用瀏覽器的writer即可, gin的輸出writer為 c.Writer// 我們這里不直接輸出到瀏覽器,而是輸出到模板文件中,所以用這個自定義的writer接收后轉為字符串輸出到模板中.buf := bytes.NewBufferString("")// 渲染模板if err := tpl.Execute(buf, data); err == nil {return template.HTML(buf.String()) // 將緩存中的所有數據以html格式放回 注意必須是template.HTML格式 否則頁面不會被解析} else {return template.HTML(err.Error())}
}
總結
動態模板解析這里的關鍵點就是如何將指定的模板文件解析為HTML字符串,一般我們常見的就是直接將模板文件解析后輸出到瀏覽器, 而這里是將模板文件解析后返回HTML格式的字符串,這就需要我們使用自定義的writer來接收模板解析后的內容,然后將這些內容返回, 注意這里在返回的時候必須使用?template.HTML 類型, 否則你返回的字符串將是被轉碼后的html,是不會被瀏覽器渲染的。
附?template包中定義的返回類型參考
我們上面就用到了下面的這個 HTML類型, 他其實就是一個string類型的類型定義, 當然如果我們希望實現動態渲染css,js 等其他內容,也需要使用下面定義的對應的類型才行哦。
package template// Strings of content from a trusted source.
type (// CSS encapsulates known safe content that matches any of:// 1. The CSS3 stylesheet production, such as `p { color: purple }`.// 2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`.// 3. CSS3 declaration productions, such as `color: red; margin: 2px`.// 4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.// See https://www.w3.org/TR/css3-syntax/#parsing and// https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style//// Use of this type presents a security risk:// the encapsulated content should come from a trusted source,// as it will be included verbatim in the template output.CSS string// HTML encapsulates a known safe HTML document fragment.// It should not be used for HTML from a third-party, or HTML with// unclosed tags or comments. The outputs of a sound HTML sanitizer// and a template escaped by this package are fine for use with HTML.//// Use of this type presents a security risk:// the encapsulated content should come from a trusted source,// as it will be included verbatim in the template output.HTML string// HTMLAttr encapsulates an HTML attribute from a trusted source,// for example, ` dir="ltr"`.//// Use of this type presents a security risk:// the encapsulated content should come from a trusted source,// as it will be included verbatim in the template output.HTMLAttr string// JS encapsulates a known safe EcmaScript5 Expression, for example,// `(x + y * z())`.// Template authors are responsible for ensuring that typed expressions// do not break the intended precedence and that there is no// statement/expression ambiguity as when passing an expression like// "{ foo: bar() }\n['foo']()", which is both a valid Expression and a// valid Program with a very different meaning.//// Use of this type presents a security risk:// the encapsulated content should come from a trusted source,// as it will be included verbatim in the template output.//// Using JS to include valid but untrusted JSON is not safe.// A safe alternative is to parse the JSON with json.Unmarshal and then// pass the resultant object into the template, where it will be// converted to sanitized JSON when presented in a JavaScript context.JS string// JSStr encapsulates a sequence of characters meant to be embedded// between quotes in a JavaScript expression.// The string must match a series of StringCharacters:// StringCharacter :: SourceCharacter but not `\` or LineTerminator// | EscapeSequence// Note that LineContinuations are not allowed.// JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not.//// Use of this type presents a security risk:// the encapsulated content should come from a trusted source,// as it will be included verbatim in the template output.JSStr string// URL encapsulates a known safe URL or URL substring (see RFC 3986).// A URL like `javascript:checkThatFormNotEditedBeforeLeavingPage()`// from a trusted source should go in the page, but by default dynamic// `javascript:` URLs are filtered out since they are a frequently// exploited injection vector.//// Use of this type presents a security risk:// the encapsulated content should come from a trusted source,// as it will be included verbatim in the template output.URL string// Srcset encapsulates a known safe srcset attribute// (see https://w3c.github.io/html/semantics-embedded-content.html#element-attrdef-img-srcset).//// Use of this type presents a security risk:// the encapsulated content should come from a trusted source,// as it will be included verbatim in the template output.Srcset string
)