Переключатель или if/elseif/else внутри HTML-шаблонов golang

У меня есть эта структура:

const (
    paragraph_hypothesis = 1<<iota
    paragraph_attachment = 1<<iota
    paragraph_menu       = 1<<iota
)

type Paragraph struct {
    Type int // paragraph_hypothesis or paragraph_attachment or paragraph_menu
}

Я хочу отображать свои абзацы Type зависимым способом.

Единственное решение, которое я нашел, было основано на специальных функциях, таких как isAttachment тестирование Type в Go и вложенных {{if}} :

{{range .Paragraphs}}
    {{if .IsAttachment}}
        -- attachement presentation code  --
    {{else}}{{if .IsMenu}}
        -- menu --
    {{else}}
        -- default code --
    {{end}}{{end}}
{{end}}

На самом деле у меня больше типов, что делает его еще более странным, загромождая как код Go с IsSomething функциями, так и шаблон с этими {{end}}.

Какое чистое решение? Есть ли какое-нибудь решение switch или if/elseif/else в шаблонах go? Или совершенно другой способ обработки этих случаев?


person Denys Séguret    schedule 07.06.2013    source источник
comment
Вы имеете в виду html-шаблоны? Ваш пример типа Paragraph не слишком ясен. Как правило, вы можете создать собственное поведение шаблона, добавив функции в FuncMap (golang.org/pkg /text/template/#Template.Funcs). Извините, я не совсем понимаю, что вы пытаетесь сделать.   -  person Intermernet    schedule 07.06.2013


Ответы (3)


Шаблоны лишены логики. У них не должно быть такой логики. Максимум логики, которую вы можете иметь, это набор if.

В таком случае вы должны сделать это следующим образом:

{{if .IsAttachment}}
    -- attachment presentation code --
{{end}}

{{if .IsMenu}}
    -- menu --
{{end}}

{{if .IsDefault}}
    -- default code --
{{end}}
person Florian Margaine    schedule 07.06.2013
comment
И нет ли другого способа протестировать Type, чем добавить isSomeValue функций? - person Denys Séguret; 07.06.2013
comment
@dystroy ну, смысл в том, чтобы вывести логику из шаблона. Так что да, у вас должна быть вспомогательная функция. Это то же самое, что вы должны делать в других технологиях всякий раз, когда используете нелогичные шаблоны. - person Florian Margaine; 07.06.2013
comment
На самом деле проблема начинается с определения IsDefault. В конце концов вы начинаете с дублирования всей логики представления, которая должна присутствовать как в шаблонах, так и в коде Go, и заканчиваете большим подробным кодом в Go для поддержки шаблона, а шаблон не приносит никакой дополнительной ценности. - person Denys Séguret; 03.07.2013
comment
Это слишком жестко, нет?... какое условие нужно оценивать по строке? @ФлорианМаргейн - person Ezeewei; 13.09.2017
comment
replace: text/template не должен иметь такой логики. with: text/template не поддерживает более сложную логику. - person Jonathan Mayer; 02.10.2017
comment
Есть else и else if - person Drew LeSueur; 28.01.2018
comment
Пакет text/template предоставляет вспомогательные функции для сложной логики. Когда {{else if .IsMenu}} будет недостаточно, вы можете сделать что-то вроде {{if and .IsMenu (not .IsAttachment)}}. - person Lars; 04.05.2020
comment
Что вообще означает Шаблоны без логики. Конечно, вы можете добавить логику в шаблон. - person Karel Bílek; 23.07.2021

Да, вы можете использовать {{else if .IsMenu}}

person mcfedr    schedule 12.07.2018
comment
Это работает. Возможно, это новая функция для шаблонов. Спасибо - person openwonk; 13.08.2018

Вы можете добиться switch функциональности, добавив пользовательские функции в template.FuncMap.

В приведенном ниже примере я определил функцию printPara (paratype int) string, которая принимает один из определенных вами типов абзаца и соответствующим образом изменяет его вывод.

Обратите внимание, что в реальном шаблоне .Paratype передается в функцию printpara. Вот как передать параметры в шаблонах. Обратите внимание, что существуют ограничения на количество и форму выходных параметров для функций, добавленных в FuncMaps. На этой странице есть полезная информация, а также первая ссылка.

package main

import (
    "fmt"
    "os"
    "html/template"
)

func main() {

    const (
        paragraph_hypothesis = 1 << iota
        paragraph_attachment = 1 << iota
        paragraph_menu       = 1 << iota
    )

    const text = "{{.Paratype | printpara}}\n" // A simple test template

    type Paragraph struct {
        Paratype int
    }

    var paralist = []*Paragraph{
        &Paragraph{paragraph_hypothesis},
        &Paragraph{paragraph_attachment},
        &Paragraph{paragraph_menu},
    }

    t := template.New("testparagraphs")

    printPara := func(paratype int) string {
        text := ""
        switch paratype {
        case paragraph_hypothesis:
            text = "This is a hypothesis\n"
        case paragraph_attachment:
            text = "This is an attachment\n"
        case paragraph_menu:
            text = "Menu\n1:\n2:\n3:\n\nPick any option:\n"
        }
        return text
    }

    template.Must(t.Funcs(template.FuncMap{"printpara": printPara}).Parse(text))

    for _, p := range paralist {
        err := t.Execute(os.Stdout, p)
        if err != nil {
            fmt.Println("executing template:", err)
        }
    }
}

Производит:

Это гипотеза

это вложение

Меню
1:
2:
3:

Выберите любой вариант:

ссылка на игровую площадку

Надеюсь, это поможет, я почти уверен, что код можно немного подчистить, но я старался придерживаться приведенного вами примера кода.

person Intermernet    schedule 08.06.2013
comment
Это интересно, но в вашем решении рендеринг абзаца в HTML сделан в Go (в printPara). Тогда, похоже, нет смысла использовать шаблон. - person Denys Séguret; 08.06.2013
comment
Печать только как демонстрация. Вы можете вставить любой код в операторы case, а не только пользовательский вывод. Вы можете обрабатывать переменные, изменять значения структур и т. д. Это действительно просто для демонстрации того, как вы можете генерировать switch подобные функции в шаблонах. - person Intermernet; 08.06.2013
comment
@Intermernet, но вы не создаете там никаких switch подобных функций в шаблонах. Думаю, я тоже хотел бы иметь лучший пример. - person Florian Margaine; 08.06.2013
comment
Извините, я до сих пор не совсем понимаю, чего вы пытаетесь достичь, golang.org/pkg/ text/template обладает всеми возможностями и функциями нативных шаблонов go. Помимо перечисленных там встроенных функций, добавление функций в FuncMap — единственный известный мне способ изменить вывод. @FlorianMargaine, функция принимает одно целое число (шаблон может быть чем-то вроде {{4 | printpara}} для меню) и внутренне изменяет свое поведение, выполняя оператор switch для этого целого числа. Это настолько близко к родному golang switch, насколько я мог эмулировать в шаблоне. - person Intermernet; 08.06.2013
comment
@Intermernet Я думаю, что мы с дистроем искали что-то вроде этого: pastebin.com/QSz0vAxk - person Florian Margaine; 09.06.2013
comment
Это именно то, что я искал. - person Denys Séguret; 10.06.2013
comment
@FlorianMargaine и @dystroy, будут ли данные, управляющие шаблоном, поступать из структур? Возможно что-то вроде type Paragraph struct{Paratype int, Text string}? - person Intermernet; 10.06.2013
comment
@Intermernet да, я удалил другие поля структуры, чтобы упростить ее (и, по моему явно неправильному мнению того времени, чтобы сделать ее более понятной). - person Denys Séguret; 10.06.2013
comment
@dystroy, хорошо, я думаю, что могу реорганизовать функцию, чтобы сделать ее близкой к тому, что вы хотите. Это интересная задача, я даже читал исходный код, чтобы попытаться определить, как операторы if работают в шаблонах. if не является одной из встроенных функций шаблона, несмотря на то, что not, and и or таковыми являются. Надеюсь скоро что-нибудь придумаю :-) - person Intermernet; 10.06.2013
comment
Хорошо, после долгого чтения кажется, что мне нужно изменить стандартную библиотеку (в частности, golang.org/pkg/text/template/parse/#NodeType , просто для начала), чтобы получить истинное выражение switch. Следующей лучшей вещью будет серия {{if switch .Type | case 1}}...{{end}} (определение пользовательских функций Switch() и Case() в FuncMap), после чего вы можете просто использовать стандартные операторы if. Что ж, за последний час или около того я многое узнал о лексерах и парсерах! Соответствующий источник, если вам интересно, находится по адресу golang.org/src/pkg. /текст/шаблон/разбор . - person Intermernet; 10.06.2013