I am attempting to convert my "\n
" to "<br/>
" in my Golang templates.
type Page struct {
HTTPMethod string
Template string
CharSet string
Slug string
MetaTitle string
MetaDescription string
MetaKeywords string
Title string
Body string
Navigation Links
Detail interface{}
}
for _, page := range pages.Pages {
page := page
router.HandleFunc(page.Slug, func(w http.ResponseWriter, r *http.Request) {
err := tmpl.ExecuteTemplate(w, page.Template, page)// page of type Page
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
}
The template looks like:
{{define "index"}}{{template "header" . }}<h1>{{.Title}}</h1><div>{{.Body}}</div>{{template "footer"}}{{end}}
I attempted to concatenate the string with:
page.Body = "Some text." htmlBRTag "More text"
Which outputs the following:
htmlBRTag := "<br/>" // -> <br/>
htmlBRTag = "<br/>" //-> <br/>
The expected outcome would be:
page.Body = "Some text.<br/>More text"
Any suggestions how to do this?
Below is replicable code that runs out of the box:
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
type Data struct {
Field1 string
Field2 string
Field3 string
}
var tmpl *template.Template
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("Recovering from panic, error is: %v \n", r)
}
}()
router := mux.NewRouter()
port := ":8085"
htmlBreak := "<br/>"
data := Data{}
data.Field1 = "Some text<br/>More text"
data.Field2 = "Some text" htmlBreak "More text"
data.Field3 = template.HTMLEscapeString(data.Field2)
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
err := tmpl.ExecuteTemplate(w, "index", data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
var err error
tmpl, err = template.ParseGlob("views/*")
if err != nil {
panic(err.Error())
}
router.PathPrefix("/").HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
http.FileServer(http.Dir("./static/")).ServeHTTP(res, req)
})
fmt.Println("Server running on localhost" port)
err = http.ListenAndServe(port, handlers.CompressHandler(router))
if err != nil {
log.Fatal(err)
}
}
And in the ./views folder I have index.html, index.html, footer.html
{{define "header"}}<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Title</title></head><body>{{end}}
{{define "index"}}{{template "header" . }}
<div>F1: {{.Field1}}</div>
<div>F2: {{.Field2}}</div>
<div>F3: {{.Field3}}</div>
{{template "footer"}}{{end}}
{{define "footer"}}</body></html>{{end}}
The current output is:
F1: Some text<br/>More text
F2: Some text<br/>More text
F3: Some text<br/>More text
The expected outcome is a line break like:
Some text
More text
CodePudding user response:
You may want to consider using a regex expression that simply replaces all of the \n's with <br/>
To do that, your code would look like this
package main
import (
"regexp"
"fmt"
)
func main() {
var re = regexp.MustCompile(`(?m)\n`)
var substitution = "<br/>"
var str = `here is some text
that have
newline characters`
fmt.Println(re.ReplaceAllString(str, substitution))
}
you can play around with regex here: https://regex101.com/codegen?language=golang
CodePudding user response:
Your question is a little vague, but I believe you may be looking for the function named HTMLEscapeString(s)
.
HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
https://pkg.go.dev/html/[email protected]#HTMLEscapeString
CodePudding user response:
Thank you for adding the example code; this makes it much easier to understand your issue. However your example still includes a lot of unnecessary code so I'll answer using this (the simpler the code the better).
Note that this answer matches my comment but as you have included an example its easier to spell it out in a way that you are more likely to understand.
The current output is actually:
<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Title</title></head><body>
<div>F1: Some text<br/>More text</div>
<div>F2: Some text<br/>More text</div>
<div>F3: Some text&lt;br/&gt;More text</div>
</body></html>
The output that you have included in your question appears to be what the browser is displaying. The browser parses the HTML sent to it and displays it - so <div>F1: Some text<br/>More text</div>
becomes F1: Some text<br/>More text
when viewed in a browser (the <br/>
is text that is displayed; not the HTML element <br/>
).
When the browser processes the HTML any escaped characters are unescaped (e.g. <
becomes <
). The reason that escaped characters are used is to prevent the browser from parsing them as HTML elements (e.g. <br>
). If you want a line break then the output needs to include <br/>
as raw text (not escaped).
Go templates automatically escape a range of characters in strings passed in as parameters. This is done for security; otherwise a user might be able to submit a string with <script>..</script>
and if you send that to another users browser it may end up running a script that could do nasty things!
If you are SURE that the text you are passing in is clean then you can use the type template.HTML
to tell the template engine that you trust this string e.g. data.Field4 = template.HTML("Some text 55" htmlBreak "More text")
.
Following is a full example (playground):
package main
import (
"html/template"
"io"
"net/http"
"net/http/httptest"
"os"
)
type Data struct {
Field1 string
Field2 string
Field3 string
Field4 template.HTML
}
var tmpl *template.Template
func main() {
htmlBreak := "<br/>"
data := Data{}
data.Field1 = "Some text<br/>More text"
data.Field2 = "Some text" htmlBreak "More text"
data.Field3 = template.HTMLEscapeString(data.Field2)
data.Field4 = template.HTML("Some text 55" htmlBreak "More text")
var err error
tmpl, err := template.New("index").Parse(`{{define "header"}}<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Title</title></head><body>{{end}}
{{define "index"}}{{template "header" . }}
<div>F1: {{.Field1}}</div>
<div>F2: {{.Field2}}</div>
<div>F3: {{.Field3}}</div>
<div>F3: {{.Field4}}</div>
{{template "footer"}}{{end}}
{{define "footer"}}</body></html>{{end}}
`)
// tmpl, err = template.ParseGlob("views/*")
if err != nil {
panic(err.Error())
}
// Now run the template (normally done in a handler)
w := httptest.NewRecorder()
if err = tmpl.ExecuteTemplate(w, "index", data); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
w.Flush()
io.Copy(os.Stdout, w.Result().Body)
}
The output is:
<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Title</title></head><body>
<div>F1: Some text<br/>More text</div>
<div>F2: Some text<br/>More text</div>
<div>F3: Some text&lt;br/&gt;More text</div>
<div>F3: Some text 55<br/>More text</div>
</body></html>
Note the <br/>
in the new line; the browser will display this as a break.