この記事はWanoグループ Advent Calendar 2021 4日目の記事になります
goのTemplateはtext/html二種類がある
しかしxml生成の際に、どっちでもそのまま使ってはいけません
例えば:
text/templateの場合
package main
import (
"bytes"
"fmt"
"text/template"
)
type XmlTemplateMeta struct {
Text string
}
func main() {
var xmlTemplateStr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test>\n <text>{{ .Text }}</text>\n</test>\n"
// & 入れたら。。。
x := XmlTemplateMeta{
Text: "test string1 & string2",
}
tmpl := template.Must(template.New("xml_template").Parse(xmlTemplateStr))
resBuffer := new(bytes.Buffer)
tmpl.Execute(resBuffer, x)
fmt.Printf("%v",resBuffer.String())
}
結果は:
<?xml version="1.0" encoding="UTF-8"?>
<test>
<text>test string1 & string2</text>
</test>
&はescapeできなかった
もしhtml/templateを使う場合:
<?xml version="1.0" encoding="UTF-8"?>
<test>
<text>test string1 & string2</text>
</test>
中身は出来ましたけど、先頭の<?xml 部分もescapeしようとしてしまう、これもダメですね
そうしたらhtml.EscapeStringを使って、中身は先に一回escapeの手もありますけど
package main
import (
"bytes"
"fmt"
"html"
"text/template"
)
type XmlTemplateMeta struct {
Text string
}
func main() {
var xmlTemplateStr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test>\n <text>{{ .Text }}</text>\n</test>\n"
x := XmlTemplateMeta{
Text: html.EscapeString("test string1 & string2"), // EscapeStringを使用
}
tmpl := template.Must(template.New("xml_template").Parse(xmlTemplateStr))
resBuffer := new(bytes.Buffer)
tmpl.Execute(resBuffer, x)
fmt.Printf("%v",resBuffer.String())
}
結果:
<?xml version="1.0" encoding="UTF-8"?>
<test>
<text>test string1 & string2</text>
</test>
但しstructの構造体に対して、中のstringを再帰的に処理がいるので、結構面倒いですね。
そこでtempalteのpipeline機能を使ってやてみます
package main
import (
"bytes"
"fmt"
"html"
"text/template"
)
type XmlTemplateMeta struct {
Text string
}
func main() {
// tempalteの中もescapeの使用をお忘れなく
var xmlTemplateStr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test>\n <text>{{escape .Text }}</text>\n</test>\n"
funcMap := map[string]interface{}{
"escape": func(str string) string {
return html.EscapeString(str)
},
}
x := XmlTemplateMeta{
Text: "test string1 & string2",
}
// funcMapの使用
tmpl := template.Must(template.New("xml_template").Funcs(funcMap).Parse(xmlTemplateStr))
resBuffer := new(bytes.Buffer)
tmpl.Execute(resBuffer, x)
fmt.Printf("%v",resBuffer.String())
}
これならescape設定は全部templateの中で完結するので、structの方気にしなくで良いですね