通过模板/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}}
管道的值必须是数组、切片、贴图或通道

也就是说,管道不能是结构。您需要:

  • 使用中间类型,例如
    []接口{}
    ,作为传递给模板的容器变量
  • 如图所示,分别键入每个单元格
  • 创建一个模板函数,将结构值转换为可以迭代的类型
由于结构是在编译时定义的,并且在运行时不会更改其结构,所以迭代是不必要的,也不会使模板中的内容更加清晰。我建议不要这样做

编辑

但有时反思是件好事。Brenden还指出,实际上可以让range迭代函数返回的值。如果使用反射,这将是最简单的方法

使用模板函数的完整工作示例:

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
。布伦登:我把它驳回了,因为我认为那是不可能的。尝试一下,我发现确实可以让一个模板函数返回一个要迭代的结构!这是一个更好的解决方案。我要补充一点——我打赌很多人会发现这很有用。