2016-11-14 8 views
1

Так что я хотел бы как-то получить все мои действия {{ .blahblah }}, определенные в шаблоне как срез строк.Golang, как получить карту или список шаблонов «действия» из проанализированного шаблона?

Например, если у меня есть этот шаблон:

<h1>{{ .name }} {{ .age }}</h1> 

Я хотел бы быть в состоянии получить []string{"name", "age"}. Притворитесь, что шаблон имеет метод func (t *Template) Fields() []string:

t := template.New("cooltemplate").Parse(`<h1>{{ .name }} {{ .age }}</h1>`) 
if t.Fields() == []string{"name", "age"} { 
    fmt.Println("Yay, now I know what fields I can pass in!") 
    // Now lets pass in the name field that we just discovered. 
    _ = t.Execute(os.Stdout, map[string]string{"name": "Jack", "age":"120"}) 
} 

Есть ли способ, чтобы проверить обработанный шаблон, как это?
Спасибо!

+0

Шаблон содержит parse.Tree который предоставляет этот вид материала (FieldNode). Формируйте документы: «Поле * parse.Tree экспортируется только для использования с помощью html/template и должно рассматриваться как не экспортированное всеми другими клиентами». Итак: Не делайте этого. Если вы не следуете этому совету: Удачи. – Volker

ответ

0

Предисловие: Как предлагает Voker, поле Template.Tree равно «экспортировано только для использования по html/template и должно рассматриваться как нераскрытое всеми другими клиентами».

Вы не должны полагаться на такую ​​вещь, чтобы иметь возможность предоставлять ввод для выполнения шаблона. Вы должны знать шаблон, который хотите выполнить, и данные, которые он ожидает. Вы не должны «исследовать» его во время выполнения, чтобы предоставить аргументы для него.


Значение, которое вы получите из разбора шаблона является template.Template (либо text/template или html/template, они имеют один и тот же API). Этот шаблон представляет шаблоны как дерево типа parse.Tree. Все, что содержит текстовый шаблон, хранится в этом дереве в узлах, включая статические тексты, действия и т. Д.

Сказав это, вы можете пройти это дерево и искать узлы, которые идентифицируют такие действия, которые получают доступ к полям или вызовам. Узлы имеют тип parse.Node, который имеет метод Node.Type(), возвращающий его тип. Возможные типы определяются как константы в пакете parse, рядом с типом parse.NodeType, например.

const (
     NodeText NodeType = iota // Plain text. 
     NodeAction     // A non-control action such as a field evaluation. 
     NodeBool     // A boolean constant. 
     NodeChain     // A sequence of field accesses. 
     NodeCommand     // An element of a pipeline. 
     NodeDot      // The cursor, dot. 

     NodeField  // A field or method name. 
     NodeIdentifier // An identifier; always a function name. 
     NodeIf   // An if action. 
     NodeList  // A list of Nodes. 
     NodeNil  // An untyped nil constant. 
     NodeNumber  // A numerical constant. 
     NodePipe  // A pipeline of commands. 
     NodeRange  // A range action. 
     NodeString  // A string constant. 
     NodeTemplate // A template invocation action. 
     NodeVariable // A $ variable. 
     NodeWith  // A with action. 
) 

Так вот пример программы, которая рекурсивно проходит шаблон дерева, и выглядит для узлов с NodeAction типа, который «акция без контроля, такие как полевой оценки.»

Это решение является просто демонстрацией, доказательством концепции, она не обрабатывает все случаи.

func ListTemplFields(t *template.Template) []string { 
    return listNodeFields(t.Tree.Root, nil) 
} 

func listNodeFields(node parse.Node, res []string) []string { 
    if node.Type() == parse.NodeAction { 
     res = append(res, node.String()) 
    } 

    if ln, ok := node.(*parse.ListNode); ok { 
     for _, n := range ln.Nodes { 
      res = listNodeFields(n, res) 
     } 
    } 
    return res 
} 

Пример использования его:

t := template.Must(template.New("cooltemplate"). 
    Parse(`<h1>{{ .name }} {{ .age }}</h1>`)) 
fmt.Println(ListTemplFields(t)) 

Выход (попробовать на Go Playground):

[{{.name}} {{.age}}] 
+0

Спасибо за ваш ответ. Чтобы уточнить, причиной, по которой вы хотите получить действия во время выполнения, является то, что вы не контролируете создание шаблона или часто меняете шаблон. Например, у меня есть шаблоны, представляющие буквы. У меня есть GUI, который позволяет пользователю вводить значения для шаблона. Очевидно, что каждый шаблон будет иметь некоторые подобные и некоторые другие действия, которые необходимо заполнить.Таким образом, GUI должен иметь возможность отображать поля ввода для каждого действия, найденного в шаблоне во время выполнения, иначе мне пришлось бы статически кодировать все поля ввода для каждого отдельного шаблона. – JackMordaunt