【问题标题】:Go template list variable to replace from template转到模板列表变量以从模板替换
【发布时间】:2021-08-15 23:21:05
【问题描述】:

所以我正在使用 go 模板,我希望能够通过从模板中获取变量列表来动态生成配置映射。

准确地说,假设我有一个文件名 test.yaml.tmpl,看起来像这样:

car:
  color: {{ .color }}
  model: {{ .model }}

我希望能够在我的 go 代码中生成一个包含 [color model][.color .model] 的数组,我可以自己处理这些点。

我查看了不同的选项,但无法得到我想要的结果,我得到的最接近的结果是使用 template.Root.Nodes 提取变量值,但它并不完美,并且可能在特定条件下产生不需要的错误。

有人有一种干净的方法来生成模板变量的数组吗?

编辑 1

我尝试使用树,这给了我这种类型的输出:

&{test.yaml.tmpl test.yaml.tmpl ---
car:
  color: {{ .color }}
  model: {{ .model }}
 0 ---
car:
  color: {{ .color }}
  model: {{ .model }}
[] <nil> [{8 995  45} {11 409 {{ 22} {0 0  0}] 1 [] map[] 0 0}

问题是我无法访问字段节点,访问树时唯一可用的方法是:

  • 错误上下文
  • 解析
  • 复制及其方法
  • 模式
  • 姓名
  • 解析名称
  • Root 和 NodeType 方法

仍然无法获取字段列表。

编辑 2

打印 tree.Root.Nodes 时,我会得到完整的 yaml 输出,其中包含要替换的变量:

(*parse.ActionNode)(0xc00007f1d0)({{ .color }}),
 (*parse.TextNode)(0xc00007f200)

【问题讨论】:

标签: go go-templates


【解决方案1】:

你可以使用你知道的正则表达式。 ;P

package main

import (
    "fmt"
    "regexp"
)

var fieldSearch = regexp.MustCompile(`{{ \..* }}`)

func main() {
    template := `
car:
  color: {{ .color }}
  model: {{ .model }}
`
    res := fieldSearch.FindAll([]byte(template), -1)
    for i := range res {
        // this is just for readability you can replace this with 
        // magic numbers if you want
        res[i] = res[i][len("{{ .") : len(res[i])-len(" }}")]
    }

    for _, v := range res {
        fmt.Println(string(v))
    }
}

【讨论】:

  • 是的,我知道...我目前正在做类似的事情,但需要更多的调整,因为您的方法没有考虑其他参数,例如:或者,如果等...所以很难正确使用,我想做一些更清洁的事情。
【解决方案2】:

好的,所以我使用@icza How to get a map or list of template 'actions' from a parsed template?发布的链接并处理返回的字符串以获得我需要的内容,结果如下:

func main() {
    node := listNodeFields(t.Tree.Root)
    var tNode []string
    for _, n := range node {
        r := n[len("{{.* .") : len(n)-len(" .*}}")]
        if strings.Contains(n, "or ") {
            r = r + " or"
        }
        tNode = append(tNode, r)
    }

    config := make(map[string]string)
    for _, n := range tNode {
        var value string
        var present bool
        if strings.Contains(n, " or") {
            n = strings.Replace(n, " or", "", -1)
            value, present = os.LookupEnv(n)
            if !present {
                fmt.Println("The variable " + value + " is not set but there is a default value in template " + t.Name() + "!")
            }
        } else {
            value, present = os.LookupEnv(n)
            if !present {
                return nil, errors.New("The variable " + f + " is not set but exists in the template " + t.Name() + "!")
            }
        }
        config[n] = value
    }
}

func listNodeFields(node parse.Node) []string {
    var res []string
    if node.Type() == parse.NodeAction {
        res = append(res, node.String())
    }
    if ln, ok := node.(*parse.ListNode); ok {
        for _, n := range ln.Nodes {
            res = append(res, listNodeFields(n)...)
        }
    }
    return res
}

由于我不想在使用默认值的情况下生成错误,所以我添加了一个特定的处理方法,以便不会从模板的 missingkey=error 选项中获取错误。

【讨论】:

    猜你喜欢
    • 2016-08-26
    • 2018-02-06
    • 2015-08-26
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多