Parsing HTML code in page shown as plain text with go Template
Asked Answered
P

2

5

I've started using the Go language, and am now trying to create an HTML page. I am quite new to both coding in Go and HTML.

In the Go program I'm trying to parse a HTML page (div) into a main html page (index.html) I'm trying to add this div to the main html page using a template in Go.

The html page where I'm trying to parse the data into looks like this:

<html>
<head>
    <meta charset="utf-8">
    <title>SmartHomePi Status</title>
    <link rel="stylesheet" href="../static/css/style.css">
</head>
<body>
    <h1>HomeControl Connection Status</h1>
    <div id="wrapper" width="100%">
        {{.SonoffBasic}}
    </div>
</body>

the {{.SonoffBasic}} part is the part where I'm trying to add my div. The div I'm trying to add looks like this:

<div id="sonoffbasicdevice">
    <span class="%connectiondotclass%"></span>
    <p id="title">%title%</p>
    <p id="tempandhum">%humstatus%</p>
    <p id="ipaddress">%ipaddress%</p>
    <p id="portnumber">%portnumber%</p>
</div>

All value's with %xxx% are parsed in go to contain useful information, and all goes correct.

But now I'm trying to parse those 2 together using a Template in Go, and here seems to go something wrong.

I'm doing that with the following function in Go:

func renderHomeKitTemplate(w http.ResponseWriter, tmpl string, items *WebPageHTMLItems) {
    err := templates.ExecuteTemplate(w, "index.html", items)
} 

Where the variable items is a struct looking like this:

type WebPageHTMLItems struct{
    SonoffBasic  string
}

where theSonoffBasic string contains the div with all filled in information.

The webpage can be viewed when I run the program, but when the webpage is shown, instead of parsing the div, it is shown as plain text, what am I doing wrong in here? HTML code shown as text

Is this even the correct way to parse the data into the HTML file. The reason why I'm using this way of adding a complete div, is because I can have multiple "sonoffbasicdevice" items and should add multiple of them.

Phlebotomy answered 18/5, 2018 at 9:48 Comment(1)
Possible duplicate of Go template.ExecuteTemplate include htmlMantissa
F
6

Using template.HTML

html/template provides automatic, context-sensitive escaping safe against code injection:

HTML templates treat data values as plain text which should be encoded so they can be safely embedded in an HTML document. The escaping is contextual, so actions can appear within JavaScript, CSS, and URI contexts.

There is a special type in the html/template package: template.HTML. Values of this type in the template are not escaped when the template is rendered.

So change the type of WebPageHTMLItems.SonoffBasic to template.HTML and it will be rendered as-is:

type WebPageHTMLItems struct{
    SonoffBasic template.HTML
}

template.HTML has string as its underlying type, so to set this field from a string value, use a simple type conversion:

params := &WebPageHTMLItems{
    SonoffBasic: template.HTML("<div>...</div>"),
}

Word of warning: this will not protect against code injection! So for example when you substitute %title% and it contains JavaScript code, that will be let through to the output and finally executed in the clients' browsers.

Using the {{template}} action

Also note that you may define you <div> as a separate, named template, and just use the {{template}} action to include it in your page, something like this:

{{define "sonoffbasicdevice"}}
    <div id="sonoffbasicdevice">
        <span class="%connectiondotclass%"></span>
        <p id="title">%title%</p>
        <p id="tempandhum">%humstatus%</p>
        <p id="ipaddress">%ipaddress%</p>
        <p id="portnumber">%portnumber%</p>
    </div>
{{end}}

And in your page template:

<div id="wrapper" width="100%">
    {{template "sonoffbasicdevice"}}
</div>

Also note that to be on the completely safe side here, you may also make and pass params to your sonoffbasicdevice template like to any other, and let the html/template package take care of safe, context sensitive substitution:

{{define "sonoffbasicdevice"}}
    <div id="sonoffbasicdevice">
        <span class="{{.Connectiondotclass}}"></span>
        <p id="title">{{.Title}}</p>
        <p id="tempandhum">{{.Humstatus}}</p>
        <p id="ipaddress">{{.Ipaddress}}</p>
        <p id="portnumber">{{.Portnumber}}</p>
    </div>
{{end}}

Then you have to include it like this (to pass params intended for it):

<div id="wrapper" width="100%">
    {{template "sonoffbasicdevice" .SonoffBasic}}
</div>

Execution of this "multi-template" could look like this:

type SonoffBasic struct {
    Connectiondotclass string
    Title              string
    Humstatus          string
    Ipaddress          string
    Portnumber         string
}

type WebPageHTMLItems struct{
    SonoffBasic *SonoffBasic
}

params := &WebPageHTMLItems{
    SonoffBasic: &SonoffBasic{
        Connectiondotclass: "someclass",
        Title:              "sometitle",
        Humstatus:          "somestatus",
        Ipaddress:          "someip",
        Portnumber:         "someport",
    },
}

err := templates.ExecuteTemplate(w, "index.html", params)
Fondafondant answered 18/5, 2018 at 11:18 Comment(1)
Thank you for this detailed explanation of how I can implement my div. And even telling me how I can do this better, I will go for the simple solution first, to see if i can get the HTML page working. And then rewrite it using {{template}} actions. As that results in safer and better looking codePhlebotomy
A
1

We have two packages for generating templates in the Golang

  1. html/template
  2. text/template

If you are sure about your data, you can use text/template instead of html/template

Atmometer answered 23/10, 2023 at 10:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.