Go语言标准库之template

[TOC] 更新、更全的《Go从入门到放弃》的更新网站,更有python、go、人工智能教学等着你:http://www.javashuo.com/article/p-mxrjjcnn-hn.htmlhtml

<p><code>html/template</code>包实现了数据驱动的模板,用于生成可对抗代码注入的安全HTML输出。它提供了和<code>text/template</code>包相同的接口,Go语言中输出HTML的场景都应使用<code>text/template</code>包。</p>python

1、模板

<p>在基于MVC的Web架构中,咱们一般须要在后端渲染一些数据到HTML文件中,从而实现动态的网页效果。</p>后端

2、模板示例

<p>经过将模板应用于一个数据结构(即该数据结构做为模板的参数)来执行,来得到输出。模板中的注释引用数据接口的元素(通常如结构体的字段或者字典的键)来控制执行过程和获取须要呈现的值。模板执行时会遍历结构并将指针表示为&rsquo;.&lsquo;(称之为&rdquo;dot&rdquo;)指向运行过程当中数据结构的当前位置的值。</p>数组

<p>用做模板的输入文本必须是utf-8编码的文本。&rdquo;Action&rdquo;—数据运算和控制单位—由&rdquo;{{&ldquo;和&rdquo;}}&ldquo;界定;在Action以外的全部文本都不作修改的拷贝到输出中。Action内部不能有换行,但注释能够有换行。</p>安全

<p>HTML文件代码以下:</p>数据结构

<pre><code class="language-html">&lt;!DOCTYPE html&gt; &lt;html lang=&quot;en&quot;&gt; &lt;head&gt; &lt;meta charset=&quot;UTF-8&quot;&gt; &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt; &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot;&gt; &lt;title&gt;Hello&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;p&gt;Hello {{.}}&lt;/p&gt; &lt;/body&gt; &lt;/html&gt; ``` <p>咱们的HTTP server端代码以下:</p> ```go // main.go func sayHello(w http.ResponseWriter, r *http.Request) { // 解析指定文件生成模板对象 tmpl, err := template.ParseFiles(&quot;./hello.html&quot;) if err != nil { fmt.Println(&quot;create template failed, err:&quot;, err) return } // 利用给定数据渲染模板,并将结果写入w tmpl.Execute(w, &quot;沙河小王子&quot;) } func main() { http.HandleFunc(&quot;/&quot;, sayHello) err := http.ListenAndServe(&quot;:9090&quot;, nil) if err != nil { fmt.Println(&quot;HTTP server failed,err:&quot;, err) return } } ``` # 模板语法 ## {{.}} <p>模板语法都包含在<code>{{</code>和<code>}}</code>中间,其中<code>{{.}}</code>中的点表示当前对象。</p> <p>当咱们传入一个结构体对象时,咱们能够根据<code>.</code>来访问结构体的对应字段。例如:</p> ```go // main.go type UserInfo struct { Name string Gender string Age int } func sayHello(w http.ResponseWriter, r *http.Request) { // 解析指定文件生成模板对象 tmpl, err := template.ParseFiles(&quot;./hello.html&quot;) if err != nil { fmt.Println(&quot;create template failed, err:&quot;, err) return } // 利用给定数据渲染模板,并将结果写入w user := UserInfo{ Name: &quot;小王子&quot;, Gender: &quot;男&quot;, Age: 18, } tmpl.Execute(w, user) } ``` <p>HTML文件代码以下:</p> <pre><code class="language-html">&lt;!DOCTYPE html&gt; &lt;html lang=&quot;en&quot;&gt; &lt;head&gt; &lt;meta charset=&quot;UTF-8&quot;&gt; &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt; &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot;&gt; &lt;title&gt;Hello&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;p&gt;Hello {{.Name}}&lt;/p&gt; &lt;p&gt;性别:{{.Gender}}&lt;/p&gt; &lt;p&gt;年龄:{{.Name}}&lt;/p&gt; &lt;/body&gt; &lt;/html&gt; ``` <p>同理,当咱们传入的变量是map时,也能够在模板文件中经过<code>.</code>根据key来取值。</p> ## 2.1 注释 <pre><code class="language-template">{{/* a comment */}} 注释,执行时会忽略。能够多行。注释不能嵌套,而且必须紧贴分界符始止。 ``` ## pipeline <p><code>pipeline</code>是指产生数据的操做。好比<code>{{.}}</code>、<code>{{.Name}}</code>等。Go的模板语法中支持使用管道符号<code>|</code>连接多个命令,用法和unix下的管道相似:<code>|</code>前面的命令会将运算结果(或返回值)传递给后一个命令的最后一个位置。</p> <p><strong>注意:</strong>并非只有使用了<code>|</code>才是pipeline。Go的模板语法中,<code>pipeline的</code>概念是传递数据,只要能产生数据的,都是<code>pipeline</code>。</p> ## 变量 <p>Action里能够初始化一个变量来捕获管道的执行结果。初始化语法以下:</p> <pre><code class="language-template">$variable := pipeline ``` <p>其中$variable是变量的名字。声明变量的action不会产生任何输出。</p> ## 2.2 条件判断 <p>Go模板语法中的条件判断有如下几种:</p> <pre><code class="language-template">{{if pipeline}} T1 {{end}} {{if pipeline}} T1 {{else}} T0 {{end}} {{if pipeline}} T1 {{else if pipeline}} T0 {{end}} ``` ## range <p>Go的模板语法中使用<code>range</code>关键字进行遍历,有如下两种写法,其中<code>pipeline</code>的值必须是数组、切片、字典或者通道。</p> <pre><code class="language-template">{{range pipeline}} T1 {{end}} 若是pipeline的值其长度为0,不会有任何输出 {{range pipeline}} T1 {{else}} T0 {{end}} 若是pipeline的值其长度为0,则会执行T0。 ``` ## 2.3 with <pre><code class="language-template">{{with pipeline}} T1 {{end}} 若是pipeline为empty不产生输出,不然将dot设为pipeline的值并执行T1。不修改外面的dot。 {{with pipeline}} T1 {{else}} T0 {{end}} 若是pipeline为empty,不改变dot并执行T0,不然dot设为pipeline的值并执行T1。 ``` ## 预约义函数 <p>执行模板时,函数从两个函数字典中查找:首先是模板函数字典,而后是全局函数字典。通常不在模板内定义函数,而是使用Funcs方法添加函数到模板里。</p> <p>预约义的全局函数以下:</p> <pre><code class="language-template">and 函数返回它的第一个empty参数或者最后一个参数; 就是说&quot;and x y&quot;等价于&quot;if x then y else x&quot;;全部参数都会执行; or 返回第一个非empty参数或者最后一个参数; 亦即&quot;or x y&quot;等价于&quot;if x then x else y&quot;;全部参数都会执行; not 返回它的单个参数的布尔值的否认 len 返回它的参数的整数类型长度 index 执行结果为第一个参数以剩下的参数为索引/键指向的值; 如&quot;index x 1 2 3&quot;返回x[1][2][3]的值;每一个被索引的主体必须是数组、切片或者字典。 print 即fmt.Sprint printf 即fmt.Sprintf println 即fmt.Sprintln html 返回其参数文本表示的HTML逸码等价表示。 urlquery 返回其参数文本表示的可嵌入URL查询的逸码等价表示。 js 返回其参数文本表示的JavaScript逸码等价表示。 call 执行结果是调用第一个参数的返回值,该参数必须是函数类型,其他参数做为调用该函数的参数; 如&quot;call .X.Y 1 2&quot;等价于go语言里的dot.X.Y(1, 2); 其中Y是函数类型的字段或者字典的值,或者其余相似状况; call的第一个参数的执行结果必须是函数类型的值(和预约义函数如print明显不一样); 该函数类型值必须有1到2个返回值,若是有2个则后一个必须是error接口类型; 若是有2个返回值的方法返回的error非nil,模板执行会中断并返回给调用模板执行者该错误; ``` ## 2.4 比较函数 <p>布尔函数会将任何类型的零值视为假,其他视为真。</p> <p>下面是定义为函数的二元比较运算的集合:</p> <pre><code class="language-template">eq 若是arg1 == arg2则返回真 ne 若是arg1 != arg2则返回真 lt 若是arg1 &lt; arg2则返回真 le 若是arg1 &lt;= arg2则返回真 gt 若是arg1 &gt; arg2则返回真 ge 若是arg1 &gt;= arg2则返回真 ``` <p>为了简化多参数相等检测,eq(只有eq)能够接受2个或更多个参数,它会将第一个参数和其他参数依次比较,返回下式的结果:</p> <pre><code class="language-template">{{eq arg1 arg2 arg3}} ``` <p>比较函数只适用于基本类型(或重定义的基本类型,如&rdquo;type Celsius float32&rdquo;)。可是,整数和浮点数不能互相比较。</p> ## 2.5 自定义函数 <p>Go的模板支持自定义函数。</p> ```go func sayHello(w http.ResponseWriter, r *http.Request) { htmlByte, err := ioutil.ReadFile(&quot;./hello.html&quot;) if err != nil { fmt.Println(&quot;read html failed, err:&quot;, err) return } // 自定义一个夸人的模板函数 kua := func(arg string) (string, error) { return arg + &quot;真帅&quot;, nil } // 采用链式操做在Parse以前调用Funcs添加自定义的kua函数 tmpl, err := template.New(&quot;hello&quot;).Funcs(template.FuncMap{&quot;kua&quot;: kua}).Parse(string(htmlByte)) if err != nil { fmt.Println(&quot;create template failed, err:&quot;, err) return } user := UserInfo{ Name: &quot;小王子&quot;, Gender: &quot;男&quot;, Age: 18, } // 使用user渲染模板,并将结果写入w tmpl.Execute(w, user) } ``` <p>咱们能够在模板文件<code>hello.html</code>中使用咱们自定义的<code>kua</code>函数了。</p> <pre><code class="language-template">{{kua .Name}} ``` ## 嵌套template <p>咱们能够在template中嵌套其余的template。这个template能够是单独的文件,也能够是经过<code>define</code>定义的template。</p> <p>举个例子: t.html文件内容以下:</p> <pre><code class="language-template">&lt;!DOCTYPE html&gt; &lt;html lang=&quot;en&quot;&gt; &lt;head&gt; &lt;meta charset=&quot;UTF-8&quot;&gt; &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt; &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot;&gt; &lt;title&gt;tmpl test&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;h1&gt;测试嵌套template语法&lt;/h1&gt; &lt;hr&gt; {{template &quot;ul.html&quot;}} &lt;hr&gt; {{template &quot;ol.html&quot;}} &lt;/body&gt; &lt;/html&gt; {{ define &quot;ol.html&quot;}} &lt;h1&gt;这是ol.html&lt;/h1&gt; &lt;ol&gt; &lt;li&gt;吃饭&lt;/li&gt; &lt;li&gt;睡觉&lt;/li&gt; &lt;li&gt;打豆豆&lt;/li&gt; &lt;/ol&gt; {{end}} ``` <p>ul.html文件内容以下:</p> <pre><code class="language-template">&lt;ul&gt; &lt;li&gt;注释&lt;/li&gt; &lt;li&gt;日志&lt;/li&gt; &lt;li&gt;测试&lt;/li&gt; &lt;/ul&gt; ``` <p>咱们注册一个<code>templDemo</code>路由处理函数.</p> ```go http.HandleFunc(&quot;/tmpl&quot;, tmplDemo) ``` <p><code>tmplDemo</code>函数的具体内容以下:</p> ```go func tmplDemo(w http.ResponseWriter, r *http.Request) { tmpl, err := template.ParseFiles(&quot;./t.html&quot;, &quot;./ul.html&quot;) if err != nil { fmt.Println(&quot;create template failed, err:&quot;, err) return } user := UserInfo{ Name: &quot;小王子&quot;, Gender: &quot;男&quot;, Age: 18, } tmpl.Execute(w, user) } ```架构

相关文章
相关标签/搜索