Go 模板中的嵌套循环

Nested loops in Go templates

编码员。 我需要在 go 模板中渲染嵌套结构数据。我想知道是否可以在 .gohtml 模板文件中处理嵌套循环。 这是我的 .gohtml 代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charser="utf-8" />
        <title>Go templates</title>
    </head>
    <body>
        <ul>
            {{range $city := .}}
                <li>
                    name: {{$city.name}}
                    hotels:
                        <ul>
                            {{range $hotel := $city.hotels}}
                                <li>
                                    name: {{$hotel.name}}
                                    address: {{$hotel.address}}
                                    zip: {{$hotel.zip}}
                                </li>
                            {{end}}
                        </ul>
                </li>
            {{end}}
        </ul>
    </body>
</html>

这里是main.go代码:

package main

import (
    "os"
    "text/template"
)

var tpl *template.Template

func init() {
    tpl = template.Must(template.New("").ParseGlob("./*.gohtml"))
}

func main() {
    type hotel struct {
        name    string
        address string
        city    string
        zip     int
    }
    type city struct {
        name   string
        hotels []hotel
    }
    type region struct {
        cities []city
    }

    hotel1 := hotel{
        "Lambda",
        "Street 19",
        "Some city",
        65530,
    }
    hotel2 := hotel{
        "Black Sea",
        "Street 21",
        "Some city",
        65543,
    }
    hotel3 := hotel{
        "Blue Sea",
        "Street 15",
        "Some city",
        54400,
    }
    hotel4 := hotel{
        "Yellow Submarine",
        "The Beatles Square",
        "Some city",
        54401,
    }
    hotel5 := hotel{
        "LolKek",
        "Cheburek",
        "Some city",
        14213,
    }

    city1 := city{
        "Some city",
        []hotel{hotel1, hotel2},
    }
    city2 := city{
        "Some city",
        []hotel{hotel3, hotel4},
    }
    city3 := city{
        "Some city",
        []hotel{hotel5},
    }

    someRegion := region{
        []city{city1, city2, city3},
    }

    tpl.ExecuteTemplate(os.Stdout, "tpl.gohtml", someRegion)
}

go run main.go时终端没有报错,但不明白为什么输出是这样的:

<!DOCTYPE html>
<html>
        <head>
                <meta charser="utf-8" />
                <title>Go templates</title>
        </head>
        <body>
                <ul>

为什么被剪掉了?

您没有看到任何错误,因为您没有检查错误,而是忽略了错误。

Template.ExecuteTemplate() returns 错误,检查一下:

if err := tpl.ExecuteTemplate(os.Stdout, "tpl.gohtml", someRegion); err != nil {
    fmt.Println(err)
}

这将输出:

template: :9:29: executing "" at <.>: range can't iterate over {[{Some city [{Lambda Street 19 Some city 65530} {Black Sea Street 21 Some city 65543}]} {Some city [{Blue Sea Street 15 Some city 54400} {Yellow Submarine The Beatles Square Some city 54401}]} {Some city [{LolKek Cheburek Some city 14213}]}]}

错误很明显:您传递了一个用于执行的结构,然后您尝试对其进行范围调整。你不能。切片范围:

{{range $city := .cities}}

这当然行不通:您必须导出结构字段才能在模板中访问它。

type region struct {
    Cities []city
}

在模板中:

{{range $city := .Cities}}

您还必须导出其他结构字段:

type hotel struct {
    Name    string
    Address string
    City    string
    Zip     int
}
type city struct {
    Name   string
    Hotels []hotel
}

经过这些更改后,它将工作并输出(在 Go Playground 上尝试):

<!DOCTYPE html>
<html>
    <head>
        <meta charser="utf-8" />
        <title>Go templates</title>
    </head>
    <body>
        <ul>

                <li>
                    name: Some city
                    hotels:
                        <ul>

                                <li>
                                    name: Lambda
                                    address: Street 19
                                    zip: 65530
                                </li>

                                <li>
                                    name: Black Sea
                                    address: Street 21
                                    zip: 65543
                                </li>

                        </ul>
                </li>

                <li>
                    name: Some city
                    hotels:
                        <ul>

                                <li>
                                    name: Blue Sea
                                    address: Street 15
                                    zip: 54400
                                </li>

                                <li>
                                    name: Yellow Submarine
                                    address: The Beatles Square
                                    zip: 54401
                                </li>

                        </ul>
                </li>

                <li>
                    name: Some city
                    hotels:
                        <ul>

                                <li>
                                    name: LolKek
                                    address: Cheburek
                                    zip: 14213
                                </li>

                        </ul>
                </li>

        </ul>
    </body>
</html>