ch4-6: review

pull/1/head
chai2010 2016-01-08 13:55:51 +08:00
parent 42502b5aa2
commit fc32f81ceb
1 changed files with 9 additions and 11 deletions

View File

@ -1,8 +1,8 @@
## 4.6. 文本和HTML模闆
前面的例子隻是最簡單的格式使用Printf是完全足夠的。但是有時候會需要複雜的打印格式這時候一般需要將格式化代碼分離出來以便更安全地脩改。這寫功能是由text/template和html/template等模闆包提供的它們提供了一個變量值填充到一個文本或HTML格式的模闆的機製。
前面的例子,隻是最簡單的格式使用Printf是完全足夠的。但是有時候會需要複雜的打印格式這時候一般需要將格式化代碼分離出來以便更安全地脩改。這寫功能是由text/template和html/template等模闆包提供的它們提供了一個變量值填充到一個文本或HTML格式的模闆的機製。
一個模闆是一個字符串或一個文件里面包含了一個或多個由雙花括號包含的action對象。大部分的字符串隻是按面值打印但是對於actions部分將觸發其它的行爲。買個actions包好了一個用模闆語言書寫的表達式一個雖然簡短但是可以輸出複雜的打印值模闆語言包含通過選擇結構體的成員、調用函數或方法、表達式控製流if-else語句和range循環語句還有其它實例化模闆等諸多特性。下面是一個簡單的模闆字符串
一個模闆是一個字符串或一個文件,里面包含了一個或多個由雙花括號包含的`{{action}}`對象。大部分的字符串隻是按面值打印但是對於actions部分將觸發其它的行爲。每個actions都包含了一個用模闆語言書寫的表達式,一個action雖然簡短但是可以輸出複雜的打印值模闆語言包含通過選擇結構體的成員、調用函數或方法、表達式控製流if-else語句和range循環語句還有其它實例化模闆等諸多特性。下面是一個簡單的模闆字符串
{% raw %}
@ -20,7 +20,7 @@ Age: {{.CreatedAt | daysAgo}} days
{% endraw %}
這個模闆先打印匹配到的issue總數然後打印每個issue的編號、創建用戶、標題還有存在的時間。每一個action都有一個當前值的概念對應點操作符寫作“.”。當前值“.”最初被初始化爲調用模闆是的參數在當前例子中對應github.IssuesSearchResult類型的變量。模闆中`{{.TotalCount}}`對應action將展開爲結構體中TotalCount成員以默認的方式打印的值。模闆中`{{range .Items}}`和`{{end}}`對應一個循環action因此它們直接的內容可能會被展開多次循環每次迭代的當前值對應當前的Items元素的值。
這個模闆先打印匹配到的issue總數然後打印每個issue的編號、創建用戶、標題還有存在的時間。對於每一個action都有一個當前值的概念對應點操作符寫作“.”。當前值“.”最初被初始化爲調用模闆是的參數在當前例子中對應github.IssuesSearchResult類型的變量。模闆中`{{.TotalCount}}`對應action將展開爲結構體中TotalCount成員以默認的方式打印的值。模闆中`{{range .Items}}`和`{{end}}`對應一個循環action因此它們直接的內容可能會被展開多次循環每次迭代的當前值對應當前的Items元素的值。
在一個action中`|`操作符表示將前一個表達式的結果作爲後一個函數的輸入類似於UNIX中管道的概念。在Title這一行的action中第二個操作是一個printf函數是一個基於fmt.Sprintf實現的內置函數所有模闆都可以直接使用。對於Age部分第二個動作是一個叫daysAgo的函數通過time.Since函數將CreatedAt成員轉換爲過去的時間長度
@ -43,7 +43,7 @@ if err != nil {
}
```
因爲模闆通常在編譯時就測試好了如果模闆解析失敗將是一個致命的錯誤。template.Must輔助函數可以簡化這個致命錯誤的處理它接受一個模闆和一個error類型的參數檢測error是否爲nil如果不是則發出panic異常然後返迴傳入的模闆。我們將在5.9節再討論這個話題。
因爲模闆通常在編譯時就測試好了如果模闆解析失敗將是一個致命的錯誤。template.Must輔助函數可以簡化這個致命錯誤的處理它接受一個模闆和一個error類型的參數檢測error是否爲nil如果不是nil則發出panic異常然後返迴傳入的模闆。我們將在5.9節再討論這個話題。
一旦模闆已經創建、註冊了daysAgo函數、併通過分析和檢測我們就可以使用github.IssuesSearchResult作爲輸入源、os.Stdout作爲輸出源來執行模闆
@ -83,7 +83,7 @@ Age: 695 days
...
```
現在讓我們轉到html/template模闆包。它使用和text/template包相同的API和模闆語言但是增加了一個將字符串自動轉義以避免輸入字符串和HTML、JavaScript、CSS或URL語法産生衝突的問題。這個特性可以避免一些長期存在的安全問題比如通過生成HTML註入攻擊通過構造一個含有惡意代碼的問題標題這些都可能讓模闆輸出錯誤的輸出從而讓他們控製頁面。
現在讓我們轉到html/template模闆包。它使用和text/template包相同的API和模闆語言但是增加了一個將字符串自動轉義特性這可以避免輸入字符串和HTML、JavaScript、CSS或URL語法産生衝突的問題。這個特性可以避免一些長期存在的安全問題比如通過生成HTML註入攻擊通過構造一個含有惡意代碼的問題標題這些都可能讓模闆輸出錯誤的輸出從而讓他們控製頁面。
下面的模闆以HTML格式輸出issue列表。註意import語句的不同
@ -119,7 +119,7 @@ var issueList = template.Must(template.New("issuelist").Parse(`
下面的命令將在新的模闆上執行一個稍微不同的査詢:
```Go
```
$ go build gopl.io/ch4/issueshtml
$ ./issueshtml repo:golang/go commenter:gopherbot json encoder >issues.html
```
@ -128,15 +128,15 @@ $ ./issueshtml repo:golang/go commenter:gopherbot json encoder >issues.html
![](../images/ch4-04.png)
圖4.4中的沒有問題會對HTML格式産生衝突,但是我們馬上將看到標題中含有`&`和`<`字符的issue。下面的命令選擇了兩個這樣的issue
圖4.4中issue沒有包含會對HTML格式産生衝突的特殊字符,但是我們馬上將看到標題中含有`&`和`<`字符的issue。下面的命令選擇了兩個這樣的issue
```
$ ./issueshtml repo:golang/go 3133 10535 >issues2.html
```
圖4.5顯示了該査詢的結果。註意html/template包已經自動將特殊字符轉義我們依然可以看到正確的字面值。如果我們使用text/template包的話這2個issue將會産生錯誤其中“&lt;”四個字符將會被當作小於字符“<”處理,同時“<link>”字符串將會被當作一個鏈接元素處理它們都會導致HTML文檔結構的改變從而導致有未知的風險。
圖4.5顯示了該査詢的結果。註意html/template包已經自動將特殊字符轉義因此我們依然可以看到正確的字面值。如果我們使用text/template包的話這2個issue將會産生錯誤其中“&amp;lt;”四個字符將會被當作小於字符“<”處理,同時“&lt;link&gt;”字符串將會被當作一個鏈接元素處理它們都會導致HTML文檔結構的改變從而導致有未知的風險。
我們也可以通過對信任的HTML字符串使用template.HTML類型來抑製這種自動轉義的行爲。還有很多采用類型命名的字符串類型對應信任的JavaScript、CSS和URL。下面的程序演示了兩個使用不同類型的相同字符串産生的不同結果A是一個普通字符串B是一個信任的template.HTML字符串類型。
我們也可以通過對信任的HTML字符串使用template.HTML類型來抑製這種自動轉義的行爲。還有很多采用類型命名的字符串類型分别對應信任的JavaScript、CSS和URL。下面的程序演示了兩個使用不同類型的相同字符串産生的不同結果A是一個普通字符串B是一個信任的template.HTML字符串類型。
![](../images/ch4-05.png)
@ -174,5 +174,3 @@ $ go doc html/template
```
**練習 4.14** 創建一個web服務器査詢一次GitHub然後生成BUG報告、里程碑和對應的用戶信息。