使用text/template
,我需要找出数组中的任何对象是否具有某个属性值。
假设我有一份人员名单(json):
[
{"name": "ANisus", "sex":"M"},
{"name": "Sofia", "sex":"F"},
{"name": "Anna", "sex":"F"}
]
使用模板,我想要输出:
Females:
Sofia
Anna
但标题Females:
只应显示实际上有sex
设置为F
的任何人。如何在模板系统中执行此操作?我的第一次尝试是使用变量:
{{$hasFemale := 0}}
{{range .}}{{if eq .sex "F"}}{{$hasFemale := 1}}{{end}}{{end}}
{{if $hasFemale}}Female:{{end}}
我没有让这个工作,因为范围内的$ hasFemale是在一个不同的范围内,与用0开始的那个不一样。我似乎无法找到改变变量的方法启动。
“工作”示例:http://play.golang.org/p/T-Ekx7n9YQ
我不能将这个逻辑移到应用程序中;它必须在模板中完成。
答案 0 :(得分:4)
我会以不同的方式解决这个问题。你通常不希望模板中有状态,它们应该很简单。
由于您只想知道数据集中是否有女性,请在数据上定义方法HasFemales
并从模板中调用它。您不一定需要定义结构,您可以使用自定义类型和这样的定义(your modified example on play):
type People []interface{}
func (p People) HasFemale() bool {
for _, v := range p {
if m, ok := v.(map[string]interface{}); !ok {
return false
} else if _, ok := m["sex"]; ok && m["sex"] == "F" {
return true
}
}
return false
}
您的模板将如下所示:
{{if .HasFemale}}Female:
{{range .}}{{if eq .sex "F"}}{{.name}}{{end}}{{end}}
{{end}}
当然,这不是一个类型安全的结构,而不像结构那么好,所以我建议
使用encoding/json
反射功能将值映射到结构并在其上定义方法。这样做的好处是能够在内部缓存.HasFemale
的结果,因此您不需要每次都进行迭代。
有关您的评论的更新:
我的Go应用程序有两个参数:1)模板文件和2)json文件。它使用数据执行模板并输出文件。然后将输出文件传递给wkhtmltopdf以生成pdf。每个模板/数据对都有我无法控制的任意数据结构,因此Go应用程序必须是通用的
在这种情况下,请HasFemale
通用。这与您在问题中所做的类似,但有利于抽象范围的嵌套,使您可以将结果存储在变量中并在整个模板中具有状态。例如:
type Data []interface{}
func (p Data) HasField(name string, value interface{}) bool {
for _, v := range p {
if m, ok := v.(map[string]interface{}); !ok {
return false
} else if _, ok := m[name]; ok && reflect.DeepEqual(m[name], value) {
return true
}
}
return false
}
使用示例:
{{$hasFemale := .HasField "sex" "F"}}
{{if $hasFemale}}Female:
{{range .}}{{if eq .sex "F"}}{{.name}}{{end}}{{end}}
{{end}}`