Golang:自定义模板“block”函数?

huangapple go评论78阅读模式
英文:

Golang: Custom template "block" functions?

问题

我想知道是否可以在Golang模板中使用自定义函数作为模板块。下面的代码展示了一个例子。

{{ custom_func . }}
This is content that "custom_func" should do something with.
{{ end }}

这个用例有点奇特和非标准。基本上,我希望模板作者能够传入一个大块的文本,其中换行等都会被保留,并且整个文本块都会传递给函数。我可以这样做:

{{ custom_func "This is a lot of text\n with many lines etc." }}

但这对于模板作者来说不太友好。最终目标是让他们能够像这样编写:

Author is writing something normal...

{{ note }}
But would like to wrap this content as a "note".

Which when passed to the "note" function, will wrap the content with appropriate divs etc.
{{ end }}

基本上,我正在尝试一个实验,看看是否可以使用纯Go模板实现类似于"markdown/reStructuredText"的内容。目前主要是一个实验。

最终,我可能需要编写一个适当的PEG解析器,但我想先看看是否可能实现这个。

英文:

I'm wondering if it's possible to use a custom function as a template block with Golang templates. The code below shows an example.

{{ custom_func . }}
This is content that "custom_func" should do something with.
{{ end }}

Use case is a bit peculiar and non-standard. Basically I want the ability for the template author to pass in large block of text where newlines etc. is respected and for that entire block of text to be passed to the function. I could have done something like:

{{ custom_func "This is a lot of text\n with many lines etc." }}

But this is not very user friendly to the template author. The end goal is for them to write something like this:

Author is writing something normal...

{{ note }}
But would like to wrap this content as a "note".

Which when passed to the "note" function, will wrap the content with appropriate divs etc.
{{ end }}

Basically I'm trying an experiment to see if I can achieve "markdown/reStructuredText"-like content with pure go templates. It's mostly an experiment for now.

Eventually I'll probably need to write a proper PEG parser for this, but I want to see if this is possible first.

答案1

得分: 3

函数的字符串参数可以用双引号 " 或反引号 ` 包裹。

在模板中用反引号包裹的字符串字面量被称为 原始字符串常量,它们的工作方式类似于 Go 源代码中的 原始字符串字面量:可以包含换行符(但不能包含转义序列)。

因此,如果你在参数中使用反引号,就可以实现你想要的效果。

例如,a.tmpl 文件内容如下:

START
{{ note `a
b\t
c
d`}}
END

加载并执行模板的应用程序代码如下:

t := template.Must(template.New("").Funcs(template.FuncMap{
	"note": func(s string) string { return "<note>\n" + s + "\n</note>" },
}).ParseFiles("a.tmpl"))

if err := t.ExecuteTemplate(os.Stdout, "a.tmpl", nil); err != nil {
	panic(err)
}

这将输出:

START
<note>
a
b\t
c
d
</note>
END

如果你在 Go 源代码中定义模板,情况会有点棘手,因为如果你在模板文本中使用反引号(因为你想要写多行),你不能在原始字符串字面量中嵌入反引号。你必须打破字面量,并连接反引号。

以下是在 Go 源文件中进行此操作的示例:

func main() {
	t := template.Must(template.New("").Funcs(template.FuncMap{
		"note": func(s string) string { return "<note>\n" + s + "\n</note>" },
	}).Parse(src))

	if err := t.Execute(os.Stdout, nil); err != nil {
		panic(err)
	}
}

const src = `START
{{ note ` + "`" + `a
b\t
c
d` + "`" + `}}
END
`

这将输出相同的结果,在 Go Playground 上尝试一下。

英文:

String arguments to functions may be wrapped both in double quotes &quot; or in backticks `.

String literals wrapped in backticks in templates are called raw string constants, and they work like raw string literals in Go source: may include newlines (and cannot contain escape sequences).

So it's possible what you want if you use backticks for the argument.

For example, a.tmpl:

START
{{ note `a
b\t
c
d`}}
END

App to load and execute the template:

t := template.Must(template.New(&quot;&quot;).Funcs(template.FuncMap{
	&quot;note&quot;: func(s string) string { return &quot;&lt;note&gt;\n&quot; + s + &quot;\n&lt;/note&gt;&quot; },
}).ParseFiles(&quot;a.tmpl&quot;))

if err := t.ExecuteTemplate(os.Stdout, &quot;a.tmpl&quot;, nil); err != nil {
	panic(err)
}

This will output:

START
&lt;note&gt;
a
b\t
c
d
&lt;/note&gt;
END

It's a bit tricky if you define the template in your Go source, as if you use backticks for the template text (because you want to write multiple lines), you can't embed backticks in a raw string literal. You have to break the literal, and concatenate the backticks.

Example doing this in a Go source file:

func main() {
	t := template.Must(template.New(&quot;&quot;).Funcs(template.FuncMap{
		&quot;note&quot;: func(s string) string { return &quot;&lt;note&gt;\n&quot; + s + &quot;\n&lt;/note&gt;&quot; },
	}).Parse(src))

	if err := t.Execute(os.Stdout, nil); err != nil {
		panic(err)
	}
}

const src = `START
{{ note ` + &quot;`&quot; + `a
b\t
c
d` + &quot;`&quot; + `}}
END
`

This will output the same, try it on the Go Playground.

huangapple
  • 本文由 发表于 2022年10月30日 08:29:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/74249779.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定