通过模板/html迭代从结构生成表
给定一个结构集合,如何使用“范围”模板迭代器打印出一个表,该表为每个结构分配一行,为每个字段分配一列值,而不明确地命名字段通过模板/html迭代从结构生成表,html,templates,reflection,iterator,go,Html,Templates,Reflection,Iterator,Go,给定一个结构集合,如何使用“范围”模板迭代器打印出一个表,该表为每个结构分配一行,为每个字段分配一列值,而不明确地命名字段 container := []Node type Node struct { Contact_id int Employer_id int First_name string Middle_name string Last_name string } 模板代码:
container := []Node
type Node struct {
Contact_id int
Employer_id int
First_name string
Middle_name string
Last_name string
}
模板代码:
{{range .container}}
<tr>
<td>{{.Prefix}}</td>
<td>{{.First_name}}</td>
<td>{{.Middle_name}}</td>
<td>{{.Last_name}}</td>
<td>{{.Contact_id}}</td>
<td>{{.Employer_id}}</td>
</tr>
{{end}}
{{range.container}
{{.Prefix}}
{{.First_name}
{{.Middle_name}
{{.Last_name}
{{.Contact_id}
{{.Employer_id}
{{end}
当我尝试使用
{{range .container}}
{{range .}}
<td>{{.}}</td>
{{end}}
{{end}}
{{range.container}
{{range.}}
{{.}}
{{end}
{{end}
我被告知我不能迭代这些值。
有什么干净的方法可以做到这一点吗 使用
html/template
,不能在结构中的字段上迭代。在程序包的中,您可以阅读:
{{range pipeline}}T1{{end}}管道的值必须是数组、切片、贴图或通道 也就是说,管道不能是结构。您需要:
- 使用中间类型,例如
,作为传递给模板的容器变量[]接口{}
- 如图所示,分别键入每个单元格
- 创建一个模板函数,将结构值转换为可以迭代的类型
package main
import (
"html/template"
"os"
"reflect"
)
type Node struct {
Contact_id int
Employer_id int
First_name string
Middle_name string
Last_name string
}
var templateFuncs = template.FuncMap{"rangeStruct": RangeStructer}
// In the template, we use rangeStruct to turn our struct values
// into a slice we can iterate over
var htmlTemplate = `{{range .}}<tr>
{{range rangeStruct .}} <td>{{.}}</td>
{{end}}</tr>
{{end}}`
func main() {
container := []Node{
{1, 12, "Accipiter", "ANisus", "Nisus"},
{2, 42, "Hello", "my", "World"},
}
// We create the template and register out template function
t := template.New("t").Funcs(templateFuncs)
t, err := t.Parse(htmlTemplate)
if err != nil {
panic(err)
}
err = t.Execute(os.Stdout, container)
if err != nil {
panic(err)
}
}
// RangeStructer takes the first argument, which must be a struct, and
// returns the value of each field in a slice. It will return nil
// if there are no arguments or first argument is not a struct
func RangeStructer(args ...interface{}) []interface{} {
if len(args) == 0 {
return nil
}
v := reflect.ValueOf(args[0])
if v.Kind() != reflect.Struct {
return nil
}
out := make([]interface{}, v.NumField())
for i := 0; i < v.NumField(); i++ {
out[i] = v.Field(i).Interface()
}
return out
}
主程序包
进口(
“html/模板”
“操作系统”
“反映”
)
类型节点结构{
联系方式
雇主id int
名字字符串
中间名称字符串
姓氏字符串
}
var templateFuncs=template.FuncMap{“rangeStruct”:RangeStructer}
//在模板中,我们使用rangeStruct来转换结构值
//变成一个我们可以迭代的切片
var htmlTemplate=`{{range.}}
{{range rangeStruct.}}{{}
{{end}
{{end}`
func main(){
容器:=[]节点{
{1,12,“阿克皮特”,“阿尼修斯”,“尼修斯”},
{2,42,“你好”,“我的”,“世界”},
}
//我们创建模板并注册模板函数
t:=template.New(“t”).Funcs(templateFuncs)
t、 错误:=t.Parse(htmlTemplate)
如果错误!=零{
恐慌(错误)
}
err=t.Execute(os.Stdout,容器)
如果错误!=零{
恐慌(错误)
}
}
//RangeStructer接受第一个参数,该参数必须是结构,然后
//返回切片中每个字段的值。它将返回零
//如果没有参数或第一个参数不是结构
func RangeStructer(args…接口{})[]接口{}{
如果len(args)=0{
归零
}
v:=reflect.ValueOf(参数[0])
如果v.Kind()!=reflect.Struct{
归零
}
out:=make([]接口{},v.NumField())
对于i:=0;i
输出:
<tr>
<td>1</td>
<td>12</td>
<td>Accipiter</td>
<td>ANisus</td>
<td>Nisus</td>
</tr>
<tr>
<td>2</td>
<td>42</td>
<td>Hello</td>
<td>my</td>
<td>World</td>
</tr>
1.
12
接受者
茴香
尼苏斯
2.
42
你好
我的
世界
代码中的
.container.Nodes
是什么?如果你想迭代容器
,只需使用.container
。我的错误,我已经纠正了上面的例子。基本上,我的想法是让应用程序以最少的干预从查询响应转到数据表。我将SQL查询中的数据直接扫描到一个结构中,然后反射出一个要在模板中迭代以创建thead的头列表。谢谢你的回复,我现在可以停止用我的头来敲这个了。我将把结构移植到值数组并迭代这些数组,然后您可以使用reflect
包来填充传递给模板的中间[]]接口{}
变量,这与您使用头反射的方式非常相似。如果时间允许,我将添加一个示例。使用编写您自己的模板方法rangeStruct
,并使用上面提到的reflect
。布伦登:我把它驳回了,因为我认为那是不可能的。尝试一下,我发现确实可以让一个模板函数返回一个要迭代的结构!这是一个更好的解决方案。我要补充一点——我打赌很多人会发现这很有用。