html / templates-用<br>替换换行符

I'm loading a text file that has newlines in it, and pass it to html/templates.

Substituting the with <br> in the loaded string, they are escaped by the template to html &lt;br&gt; and displayed in the browser, instead of causing a line return.

How can I change this behavior without switching to text/templates (which doesn't have XSS protection)?

It seems you could run template.HTMLEscape() on your text first to sanitize it, then do the to
substitution that you trust, then use that as pre-escaped and trusted template data.

Update: Expanding on Kocka's example, this is what I had in mind:

package main

import (
    "html/template"
    "os"
    "strings"
)

const page = `<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <p>{{.}}</p>
  </body>
</html>`

const text = `first line
<script>dangerous</script>
last line`

func main() {
    t := template.Must(template.New("page").Parse(page))
    safe := template.HTMLEscapeString(text)
    safe = strings.Replace(safe, "
", "<br>", -1)
    t.Execute(os.Stdout, template.HTML(safe)) // template.HTML encapsulates a known safe HTML document fragment.
}

http://play.golang.org/p/JiH0uD5Zh2

Output is

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <p>first line<br>&lt;script&gt;dangerous&lt;/script&gt;<br>last line</p>
  </body>
</html>

And text rendered in the browser is

first line
<script>dangerous</script>
last line

Not sure where you're substituting for <br> but if it's in go, you can cast the string as template.HTML so it's not escaped.

See: http://golang.org/pkg/html/template/#HTML

If it's in a template, there should be a pipeline available, {{. | html}}

You can do it like this:

package main

import (
    "html/template"
    "os"
)

const page = `<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <p>{{.}}</p>
  </body>
</html>`

func main() {
    t := template.Must(template.New("page").Parse(page))
    t.Execute(os.Stdout, template.HTML("<br>"))
}

Try it out!

It is unnecessary to pass your entire template as an unsafe template (and this is bad practice).

You should pass a map to your template, and only explicitly 'unsafe' the elements you want to use as such, eg.

package main

import "bytes"
import "fmt"
import "html/template"
import "strings"

var input = `
  {{ define "LAYOUT" }}
    <html>
      <body>
        {{ template "CONTENT" . }}
      </body>
    </html>
  {{ end }}

  {{ define "CONTENT" }}
    Unsafe content: {{ .Unsafe }}
    Newlines converted to <br/> follow:
    {{ .Normal }}
  {{ end }}

  {{ template "LAYOUT" . }}
`

var other = `
  Hello
  World
  Again
`

var other2 = `
  <script>alert("Owned!");</script>
`

func main() {

    var t, err = template.New("sample").Parse(input)
    if err != nil {
        panic(err)
    }

    var fixed = strings.Replace(other, "
", "
<br/>", -1)
    var model = map[string]interface{}{
        "Normal": template.HTML(fixed),
        "Unsafe": other2,
    }

    var out bytes.Buffer
    t.Execute(&out, model) # <--- !! Notice the model is NOT an HTML type.

    var raw = out.String()
    fmt.Printf("%s", raw)
}

Yields:

Unsafe content:    &lt;script&gt;alert(&#34;Owned!&#34;);&lt;/script&gt;

Newlines converted to <br/> follow:
 <br/>  Hello 
 <br/>  World 
 <br/>  Again 
 <br/>

  </body>
</html>