golang实现Closure模板规范的Soy模板引擎插件Soy的使用
golang实现Closure模板规范的Soy模板引擎插件Soy的使用
Go语言实现的Soy模板引擎是遵循Google Closure Templates规范的模板引擎。下面是一个完整的使用示例:
安装
go get github.com/robfig/soy
基本使用示例
package main
import (
"fmt"
"github.com/robfig/soy"
"github.com/robfig/soy/data"
)
func main() {
// 1. 创建模板集合
templateSet := soy.NewSet()
// 2. 添加模板内容
err := templateSet.AddTemplate("example.soy", `
{namespace example}
/**
* Greets a person using "Hello" by default.
* @param name The person's name.
* @param? greetingWord Optional greeting word to use instead of "Hello".
*/
{template .hello}
{$greetingWord ?: 'Hello'}, {$name}!
{/template}
`)
if err != nil {
panic(err)
}
// 3. 编译模板集合
if err := templateSet.Compile(); err != nil {
panic(err)
}
// 4. 渲染模板
// 创建模板参数
params := data.Map{
"name": data.String("World"),
}
// 渲染模板
result, err := templateSet.Render("example.hello", params)
if err != nil {
panic(err)
}
fmt.Println(result) // 输出: Hello, World!
}
带参数的模板示例
package main
import (
"fmt"
"github.com/robfig/soy"
"github.com/robfig/soy/data"
)
func main() {
templateSet := soy.NewSet()
err := templateSet.AddTemplate("user.soy", `
{namespace user}
/**
* Displays user information
* @param user The user object containing name and email
*/
{template .profile}
<div class="profile">
<h1>{$user.name}</h1>
<p>Email: {$user.email}</p>
{if $user.age}
<p>Age: {$user.age}</p>
{/if}
</div>
{/template}
`)
if err != nil {
panic(err)
}
if err := templateSet.Compile(); err != nil {
panic(err)
}
// 创建用户数据
userData := data.Map{
"user": data.Map{
"name": data.String("John Doe"),
"email": data.String("john@example.com"),
"age": data.Int(30),
},
}
result, err := templateSet.Render("user.profile", userData)
if err != nil {
panic(err)
}
fmt.Println(result)
/* 输出:
<div class="profile">
<h1>John Doe</h1>
<p>Email: john@example.com</p>
<p>Age: 30</p>
</div>
*/
}
循环和条件示例
package main
import (
"fmt"
"github.com/robfig/soy"
"github.com/robfig/soy/data"
)
func main() {
templateSet := soy.NewSet()
err := templateSet.AddTemplate("products.soy", `
{namespace products}
/**
* Displays a list of products
* @param products List of products to display
*/
{template .list}
<ul>
{foreach $product in $products}
<li>
{$product.name} - ${$product.price}
{if $product.inStock}
(In Stock)
{else}
(Out of Stock)
{/if}
</li>
{ifempty}
<li>No products available</li>
{/foreach}
</ul>
{/template}
`)
if err != nil {
panic(err)
}
if err := templateSet.Compile(); err != nil {
panic(err)
}
// 创建产品列表数据
products := data.List{
data.Map{
"name": data.String("Laptop"),
"price": data.Float(999.99),
"inStock": data.Bool(true),
},
data.Map{
"name": data.String("Phone"),
"price": data.Float(699.99),
"inStock": data.Bool(false),
},
}
result, err := templateSet.Render("products.list", data.Map{"products": products})
if err != nil {
panic(err)
}
fmt.Println(result)
/* 输出:
<ul>
<li>Laptop - $999.99 (In Stock)</li>
<li>Phone - $699.99 (Out of Stock)</li>
</ul>
*/
}
注意事项
- 项目需要Go 1.12或更高版本
- 使用前确保设置环境变量
GO111MODULE=on
以启用go mod依赖版本管理 - 模板语法遵循Google Closure Templates规范
更多关于golang实现Closure模板规范的Soy模板引擎插件Soy的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现Closure模板规范的Soy模板引擎插件Soy的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang实现Soy模板引擎插件
Soy模板(又称Closure模板)是Google开发的一种模板语言,主要用于JavaScript和Java环境。下面我将介绍如何在Golang中实现一个支持Soy模板规范的插件。
基本实现思路
在Golang中实现Soy模板引擎,我们需要:
- 解析Soy模板语法
- 构建模板AST(抽象语法树)
- 实现模板渲染逻辑
- 提供数据绑定接口
示例实现
以下是一个简化版的Soy模板引擎实现:
package soy
import (
"bytes"
"fmt"
"regexp"
"strings"
"text/template"
)
// SoyEngine 是Soy模板引擎的核心结构
type SoyEngine struct {
templates map[string]*template.Template
funcMap template.FuncMap
}
// New 创建一个新的Soy模板引擎
func New() *SoyEngine {
return &SoyEngine{
templates: make(map[string]*template.Template),
funcMap: make(template.FuncMap),
}
}
// RegisterFunc 注册自定义函数
func (e *SoyEngine) RegisterFunc(name string, fn interface{}) {
e.funcMap[name] = fn
}
// Parse 解析Soy模板
func (e *SoyEngine) Parse(name, content string) error {
// 预处理Soy模板,转换为Go模板语法
goTpl, err := soyToGoTemplate(content)
if err != nil {
return err
}
tpl := template.New(name).Funcs(e.funcMap)
tpl, err = tpl.Parse(goTpl)
if err != nil {
return err
}
e.templates[name] = tpl
return nil
}
// Render 渲染模板
func (e *SoyEngine) Render(name string, data interface{}) (string, error) {
tpl, ok := e.templates[name]
if !ok {
return "", fmt.Errorf("template %s not found", name)
}
var buf bytes.Buffer
if err := tpl.Execute(&buf, data); err != nil {
return "", err
}
return buf.String(), nil
}
// soyToGoTemplate 将Soy模板转换为Go模板语法
func soyToGoTemplate(soy string) (string, error) {
// 替换变量引用 {$.var} -> {{.var}}
re := regexp.MustCompile(`\{\$([a-zA-Z0-9_.]+)\}`)
goTpl := re.ReplaceAllString(soy, "{{.$1}}")
// 替换if语句 {if $var} -> {{if .var}}
re = regexp.MustCompile(`\{if \$([a-zA-Z0-9_.]+)\}`)
goTpl = re.ReplaceAllString(goTpl, "{{if .$1}}")
// 替换foreach {foreach $item in $list} -> {{range .list}}
re = regexp.MustCompile(`\{foreach \$([a-zA-Z0-9_]+) in \$([a-zA-Z0-9_.]+)\}`)
goTpl = re.ReplaceAllString(goTpl, "{{range .$2}}")
// 替换模板调用 {call .template} -> {{template "template" .}}
re = regexp.MustCompile(`\{call ([a-zA-Z0-9_.]+)\}`)
goTpl = re.ReplaceAllString(goTpl, `{{template "$1" .}}`)
return goTpl, nil
}
使用示例
package main
import (
"fmt"
"github.com/yourusername/soy"
)
func main() {
// 创建引擎实例
engine := soy.New()
// 注册自定义函数
engine.RegisterFunc("upper", strings.ToUpper)
// 定义Soy模板
templateContent := `
{namespace example}
/**
* 欢迎模板
* @param name 用户名
*/
{template .welcome}
<html>
<head><title>Welcome</title></head>
<body>
<h1>Hello, {$name}!</h1>
{if $showDetails}
<p>Your name in uppercase: {upper($name)}</p>
{/if}
</body>
</html>
{/template}
`
// 解析模板
if err := engine.Parse("welcome", templateContent); err != nil {
panic(err)
}
// 准备数据
data := map[string]interface{}{
"name": "John Doe",
"showDetails": true,
}
// 渲染模板
result, err := engine.Render("welcome", data)
if err != nil {
panic(err)
}
fmt.Println(result)
}
高级功能实现
要实现更完整的Soy模板支持,还需要添加以下功能:
- 命名空间支持:
// 在soyToGoTemplate中处理命名空间
re = regexp.MustCompile(`\{namespace ([a-zA-Z0-9_.]+)\}`)
goTpl = re.ReplaceAllString(goTpl, "")
- 模板继承:
// 处理模板继承关系
re = regexp.MustCompile(`\{delpackage ([a-zA-Z0-9_.]+)\}`)
goTpl = re.ReplaceAllString(goTpl, "")
- 更复杂的数据访问:
// 处理嵌套数据访问 {$.user.name} -> {{.user.name}}
re = regexp.MustCompile(`\{\$([a-zA-Z0-9_.]+)\}`)
goTpl = re.ReplaceAllString(goTpl, "{{.$1}}")
- 循环索引:
// 处理foreach循环索引
re = regexp.MustCompile(`\{foreach \$([a-zA-Z0-9_]+) in \$([a-zA-Z0-9_.]+)\}`)
goTpl = re.ReplaceAllString(goTpl, "{{range $index, $1 := .$2}}")
性能优化建议
- 预编译模板
- 使用缓存机制
- 实现模板片段缓存
- 使用并发安全的模板引擎
完整实现建议
对于生产环境使用,建议考虑以下开源项目:
github.com/robfig/soy
- 一个完整的Soy模板引擎实现github.com/go-template/soy
- 另一个Golang Soy模板实现
这些项目提供了更完整的Soy模板规范支持,包括:
- 完整的语法解析
- 模板继承
- 国际化支持
- 自动转义
- 模板组合
以上实现提供了一个基础框架,你可以根据实际需求进行扩展和完善。