Home > other >  Newline to <br/>
Newline to <br/>

Time:11-05

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 := "&lt;br/&gt;" // -> &lt;br/&gt;
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&lt;br/&gt;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&lt;br/&gt;More text</div>
<div>F2: Some text&lt;br/&gt;More text</div>
<div>F3: Some text&amp;lt;br/&amp;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&lt;br/&gt;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. &lt; 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&lt;br/&gt;More text</div>
<div>F2: Some text&lt;br/&gt;More text</div>
<div>F3: Some text&amp;lt;br/&amp;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.

  • Related