如何使用golang模板missingkey选项?

时间:2016-02-24 20:30:09

标签: go

我希望

t, err := template.New("t1").Option("missingkey=error").Parse("{{index . \"/foo/bar\"}}")        
err = t.Execute(os.Stdout, d)

如果地图“'”返回错误没有钥匙' / foo / bar'但一切都很好。我错过了什么吗?

这里是游乐场: http://play.golang.org/p/Oqg1Dy4h1k

2 个答案:

答案 0 :(得分:2)

missingkey选项不适用于index。使用.<field-name>访问地图时,您只能获得所需的结果:

t, err := template.New("t1").Option("missingkey=error").Parse(`{{.foo}}`)
err = t.Execute(os.Stdout, d)

您可以通过定义自己的索引函数来解决此问题,该函数在缺少键时返回错误:

package main

import (
    "errors"
    "fmt"
    "os"
    "text/template"
)

func lookup(m map[string]interface{}, key string) (interface{}, error) {
    val, ok := m[key]
    if !ok {
        return nil, errors.New("missing key " + key)
    }
    return val, nil
}

func main() {
    d := map[string]interface{}{
        "/foo/bar": 34,
    }
    fns := template.FuncMap{
        "lookup": lookup,
    }
    t, err := template.New("t1").Funcs(fns).Parse(`{{ lookup . "/foo/baz" }}`)
    if err != nil {
        fmt.Println("ERROR 1")
    }
    err = t.Execute(os.Stdout, d)
    if err != nil {
        fmt.Println("ERROR 2")
    }
}

https://play.golang.org/p/L12lFnJig_

答案 1 :(得分:0)

你好@ user5976738及所有。

对于该问题,我有另一种解决方案,完全不需要模板功能,它使用text/template/parse包。

此替代方法可能对某些人非常有用。 示例用法:

if missingKeys, ok := IsMissingKeys(err); ok{
   for _, key := range missingKeys{ println(key) }
}

源代码:

package main

import (
    "fmt"
    "os"
    "strings"
    "strconv"
    "text/template"
    templateparse "text/template/parse"
)

type errMissingKeys struct {
    Keys         []string
    TemplateName string
}

func (err errMissingKeys) Error() string {
    return fmt.Sprintf("template: %s: map has no entry for keys: %s", err.TemplateName, strings.Join(err.Keys, ", "))
}

// IsMissingKeys reports whether an "err" is caused by template missing keys.
//
// Usage:
// if missingKeys, ok := IsMissingKeys(err); ok{
//     for _, key := range missingKeys{ println(key) }
// }
func IsMissingKeys(err error) ([]string, bool) {
    if err != nil {
        if v, ok := err.(errMissingKeys); ok {
            return v.Keys, true
        }
    }

    return nil, false
}

func main() {
    data := map[string]interface{}{
        "bar": 34,
    }

    tmpl, err := template.New("myTemplate").Option("missingkey=error").Parse(`{{.baz}} {{.other}}`)
    if err != nil {
        fmt.Println(err.Error())
        os.Exit(1)
    }

    err = tmpl.Execute(os.Stdout, data)
    if err != nil {
        if strings.Contains(err.Error(), "map has no entry for key ") {
            // Check if a field is not a "data" match,
            // which will lead on execute error on first undefined (missingkey=error).
            // So collect all these keys so we can have a typed error with all unknown keys listed.
            var missingKeys []string
            for _, n := range tmpl.Root.Nodes {
                if n.Type() == templateparse.NodeAction {
                    key := strings.TrimFunc(n.String(), func(r rune) bool {
                        return r == '{' || r == '}' || r == ' ' || r == '.'
                    })

                    if key == "" {
                        continue
                    }

                    if _, ok := data[key]; !ok {
                        missingKeys = append(missingKeys, strconv.Quote(key))
                    }
                }
            }

            // if just one then keep the original error which contains the full context,
            // else set to custom error type which will keep the missing keys for caller's further use.
            if len(missingKeys) > 1 {
                err = errMissingKeys{TemplateName: tmpl.Name(), Keys: missingKeys}
            }
        }
        fmt.Println(err.Error())
        os.Exit(1)
    }
}

游乐场链接:https://play.golang.org/p/JMwBpU2KyP2

最好的问候,Gerasimos Maropoulos-https://iris-go.com

的创建者