How to trim empty rows in Go templates?

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

How to trim empty rows in Go templates?

问题

go版本 go1.16.3 windows/amd64

我使用template/html包。如果我将一个变量设置到html中,

示例

  {{range $kk, $vv := .Users -}}
      {{if eq $vv.Id $performedBy}}
          {{$pSurname = $vv.ContactData.Surname}} {{$pName = $vv.ContactData.Name}}
      {{- end}}
  {{- end}}

每当我在range中填充一个变量时,它会写入一个空行。我该怎么做才能防止这种情况再次发生?

英文:

go version go1.16.3 windows/amd64

I use the template/html package. If I set a variable into html,

Example

  {{range $kk, $vv := .Users -}}
      {{if eq $vv.Id $performedBy}}
          {{$pSurname = $vv.ContactData.Surname}} {{$pName = $vv.ContactData.Name}}
      {{- end}}
  {{- end}}

Whenever I fill a variable in a range, it writes me an empty row. What can I do to prevent this from happening again?

答案1

得分: 7

text/template包的文档,文本和空格部分:

默认情况下,在执行模板时,所有动作之间的文本都会被逐字复制。[...]

然而,为了帮助格式化模板源代码,如果一个动作的左定界符(默认为“{{”)紧接着是一个减号和空白字符,那么紧接在其前面的文本中的所有尾部空白字符都会被修剪掉。类似地,如果右定界符(“}}”)之前有空白字符和减号,那么紧接在其后面的文本中的所有前导空白字符都会被修剪掉。在这些修剪标记中,空白字符必须存在:“{{- 3}}”类似于“{{3}}”,但会修剪掉紧接在其前面的文本,而“{{-3}}”会被解析为包含数字-3的动作。

TLDR; 模板中的所有(空白)空格都会在动作之间保留。如果你不想要它们,可以在动作的开头定界符之后或者结束定界符之前使用减号-来修剪前导或尾部的空格。

你必须根据你想要的输出缩进你的模板,或者使用-符号来修剪格式化的缩进。

你的{{if}}动作的主要问题是:

  {{if eq $vv.Id $performedBy}}
      {{$pSurname = $vv.ContactData.Surname}} {{$pName = $vv.ContactData.Name}}
  {{- end}}

{{if}}的结束定界符之后有一个换行符,如果{{if}}的主体被执行,这个换行符将被保留。{{- end}}中的-符号只会修剪紧接在这个{{- end}}之前的换行符(在变量赋值之后的那个换行符),但不会修剪在{{if}}末尾的那个换行符。

例如,使用以下模板:

const src = `{{$performedBy := "1"}}{{$pSurname := ""}}{{$pName := "" -}}
{{range $kk, $vv := .Users -}}
User idx: {{$kk}}
{{if eq $vv.Id $performedBy -}}
	{{- $pSurname = $vv.ContactData.Surname -}} {{- $pName = $vv.ContactData.Name -}}
{{- end -}}
{{- end}}`

进行测试:

type CData struct {
	Surname, Name string
}

type User struct {
	Id          string
	ContactData CData
}

func main() {
	t := template.Must(template.New("").Parse(src))

	p := map[string]interface{}{
		"Users": []User{
			{Id: "1", ContactData: CData{"Foo", "Bar"}},
			{Id: "2", ContactData: CData{"Foo2", "Bar2"}},
			{Id: "1", ContactData: CData{"Foo3", "Bar3"}},
			{Id: "4", ContactData: CData{"Foo4", "Bar4"}},
		},
	}

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

输出结果(在Go Playground上尝试):

User idx: 0
User idx: 1
User idx: 2
User idx: 3
英文:

Package doc of text/template, Text and spaces:

> By default, all text between actions is copied verbatim when the template is executed. [...]
>
> However, to aid in formatting template source code, if an action's left delimiter (by default "{{") is followed immediately by a minus sign and white space, all trailing white space is trimmed from the immediately preceding text. Similarly, if the right delimiter ("}}") is preceded by white space and a minus sign, all leading white space is trimmed from the immediately following text. In these trim markers, the white space must be present: "{{- 3}}" is like "{{3}}" but trims the immediately preceding text, while "{{-3}}" parses as an action containing the number -3.

TLDR; all (white) space in the template is preserved between actions. If you don't want them, you may use a minus - sign after the opening delimeter or before the closing delimeter of the action "in place" to trim the leading or trailing white spaces.

You have to indent your template how you want the output, or use the - sign to trim the formatting indentation.

The main problem with your {{if}} action:

  {{if eq $vv.Id $performedBy}}
      {{$pSurname = $vv.ContactData.Surname}} {{$pName = $vv.ContactData.Name}}
  {{- end}}

There is a newline after the closing delimeter of {{if}}, which will be preserved if the body of {{if}} is executed. The - sign in {{- end}} only trims the newline preceeding this {{- end}} (the one being after the variable assignments), but not that being at the end of {{if}}.

For example using this template:

const src = `{{$performedBy := "1"}}{{$pSurname := ""}}{{$pName := "" -}}
{{range $kk, $vv := .Users -}}
User idx: {{$kk}}
{{if eq $vv.Id $performedBy -}}
	{{- $pSurname = $vv.ContactData.Surname -}} {{- $pName = $vv.ContactData.Name -}}
{{- end -}}
{{- end}}`

Testing it:

type CData struct {
	Surname, Name string
}

type User struct {
	Id          string
	ContactData CData
}

func main() {
	t := template.Must(template.New("").Parse(src))

	p := map[string]interface{}{
		"Users": []User{
			{Id: "1", ContactData: CData{"Foo", "Bar"}},
			{Id: "2", ContactData: CData{"Foo2", "Bar2"}},
			{Id: "1", ContactData: CData{"Foo3", "Bar3"}},
			{Id: "4", ContactData: CData{"Foo4", "Bar4"}},
		},
	}

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

Output (try it on the Go Playground):

User idx: 0
User idx: 1
User idx: 2
User idx: 3

huangapple
  • 本文由 发表于 2021年6月15日 19:30:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/67985414.html
匿名

发表评论

匿名网友

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

确定