Remove spaces around passed argument via html/template - go

When i pass argument to onclick function i got spaces around that argument, why and how remove them?
t, _ := template.New("").Parse(`<div onclick="test({{.}})">{{.}}</div>`)
t.Execute(os.Stdout, 1)
Result:
<div onclick="test( 1 )">1</div>
playground
Edit:
Updated by Dave help, from template we can do something like this:
t, _ := template.New("").Funcs(template.FuncMap{
"test": func(i interface{}) template.JS {
switch i.(type) {
case int:
s := strconv.Itoa(i.(int))
return template.JS(s)
// other types
default:
panic("bad type")
}
},
}).Parse(`<div onclick="test({{test .}})">{{.}}</div>`)
t.Execute(os.Stdout, 1)
playground

It's a result of Golang doing some things to ensure that malicious JS doesn't end up in your template. If you specify that what you are passing in is safe for javascript, it will work fine.
type JS
Use of this type presents a security risk: the encapsulated content should come from a trusted source, as it will be included verbatim in the template output.
https://play.golang.org/p/TUOECg1YDtl
t.Execute(os.Stdout, template.JS("1"))
Result:
<div onclick="test(1)">1</div>

Related

Go template post processing: is it possible?

In my template, I use a sub-template that generates a piece of output.
The template output must be shifted though (because the output is in YAML format).
Is there any possibility to post-process template output?
{{ template "subtemplate" | indent 10 }}
This indent 10 is fictional, just to explain what I need.
It is possible (as #icza suggested) to save the output
into a variable and then work with it,
but maybe there is a better, more elegant approach?
{{$var := execTempl "subtemplate"}}
{{$var}}
The closest you can get to {{ template "subtemplate" | indent 10 }} is to define a function that parses and executes the subtemplate and outputs the result as string.
var externalTemplates = map[string]*template.Template{
"subtemplate": template.Must(template.New("subtemplate").Parse(sub_template)),
}
// Executes external template, must be registered with FuncMap in the main template.
func xtemplate(name string) (string, error) {
var b bytes.Buffer
if err := externalTemplates[name].ExecuteTemplate(&b, name, nil); err != nil {
return "", err
}
return b.String(), nil
}
t := template.Must(template.New("t").Funcs(template.FuncMap{
"xtemplate": xtemplate, // register func
}).Parse(main_template))
In the main template you can then use the function like this:
{{ xtemplate "subtemplate" | indent 10 }}
https://play.golang.org/p/brolOLFT4xL

How to omit a secondary return from a function call during a struct value assignment

I would like to assign a value within a variable declaration of type struct, however, I need to call a function that returns a secondary value (an error) which I would like to disregard in the assignment.
Is there a way to do so? For example:
type myStruct struct{
address common.Address
}
func main() {
newVar := myStruct{
address: common.HexToAddress("xyz")
}
}
The issue is that common.HexToAddress() returns 2 values, a common.Address as well as an error. I would like to omit the error and assign it as above. I would prefer not to have to do:
var newVar2 myStruct
myStruct,_ = common.HexToAddress("xyz")
It's usually not exactly recommended to ignore errors, which may be one reason why the language does not make this easy.
That being said, a pattern you see sometimes is a package offering a Must function, for those cases where just doing a panic() on an error is the right thing to do; e.g., when initializing package-level variables.
For example, there's text/template.Must. The implementation simply tests the error and panics if it is not nil. You can consider adding such a function as well (possibly local to your file), allowing you to write your struct initialization as:
newVar := myStruct{
address: must(common.HexToAddress("xyz")),
}
// ...
func must(address common.Address, err error) common.Address { ... }
This relies on the feature that if a function returns multiple values, and another function takes the same amount of parameters, you can invoke the latter directly on the return values of the former.
If you don't want to go that far, you do need to explicitly ignore the second return value by assigning it to the blank identifier _. You could of course do that separately, so that you still get to use a structure literal, but it may not be any cleaner than what you suggested originally:
address, _ := common.HexToAddress("xyz")
newVar := myStruct{address: address}
You're probably looking for some kind of syntactic sugar. Go is intentionally sparse on such things, because in the opinion of the language designers, it tends to make things less obvoius, thus less readable. So you have limited options here.
If you really don't care about the error, here are your options:
Assign to a temporary variable as you suggested (usually the most natural/readable option):
addr, _ := common.HexToAddress("xyz")
newVar := myStruct{
address: addr,
}
Use the return value of an anonymous function:
newVar := myStruct{
address: func() common.Address { addr, _ := common.HexToAddress("xyz"); return addr }(),
}
If you control the common package, consider adding a variant that ignores (or panics on) errors:
newVar := myStruct{
address: common.MustHexToAddress("xyz"),
}
Write your own wrapper function:
func hexToAddress(hex string) common.Address {
addr, _ := common.HexToAddress(hex)
return addr
}
newVar := myStruct{
address: hexToAddress("xyz"),
}

escape template in range

I want to print user list like: <#user1> <#user2>, this is an internal format in my company internal, but the golang template always escape the < to <. My code:
tpl, _ := template.New("text").Parse(`{{range .Users}} <#{{.}}> {{end}}`)
var buffer bytes.Buffer
tpl.Execute(&buffer, struct {
Users []string
}{
Users: []string{"user1", "user2"},
})
fmt.Println(buffer.String())
expect:
<#user1> <#user2>
output:
<#user1> <#user2>
How to fix this?
If you want to do so, use text/template. Here's a part of documentation for better understanding each:
Godoc: html/template:
This package wraps package text/template so you can share its template API to parse and execute HTML templates safely.
tmpl, err := template.New("name").Parse(...)
// Error checking elided
err = tmpl.Execute(out, data)
If successful, tmpl will now be injection-safe. Otherwise, err is an error defined in the docs for ErrorCode.
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.
The security model used by this package assumes that template authors are trusted, while Execute's data parameter is not. More details are provided below.
Example
import "text/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
produces
Hello, <script>alert('you have been pwned')</script>!
but the contextual autoescaping in html/template
import "html/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
produces safe, escaped HTML output
Hello, <script>alert('you have been pwned')</script>!

How to return unique elements in an array using Go's text/template package?

I am new to Go and I am struggling trying to figure out a way to return unique variables from an array in Go templating language. This is to configure some software and I do not have access to the source to change the actual program only the template.
I have knocked up an example in the Go playground:
https://play.golang.org/
package main
import "os"
import "text/template"
func main() {
var arr [10]string
arr[0]="mice"
arr[1]="mice"
arr[2]="mice"
arr[3]="mice"
arr[4]="mice"
arr[5]="mice"
arr[6]="mice"
arr[7]="toad"
arr[8]="toad"
arr[9]="mice"
tmpl, err := template.New("test").Parse("{{range $index, $thing := $}}The thing is: {{$thing}}\n{{end}}")
if err != nil { panic(err) }
err = tmpl.Execute(os.Stdout, arr)
if err != nil { panic(err) }
}
Right now this returns:
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: mice
The thing is: toad
The thing is: toad
The thing is: mice
What I am trying to do is craft a template that from the input array filters duplicates and only returns:
The thing is: mice
The thing is: toad
I am really stuck as I know virtually no go and struggle to find any array manipulation methods in the docs. Any one have any tips?
Addenium
Sorry for not being clear I wrote this question on the bus on the way to work.
I don't have access to any go code outside the template. I have a template I can edit and within that template I have an array that may or may not have multiple values and I need to print them once.
I appreciate this is not how templates are meant to work but if there is some dirty way to do this it would save me several days work.
You can create your own functions for the template via template.FuncMap:
arr := []string{
"mice",
"mice",
"mice",
"mice",
"mice",
"mice",
"mice",
"toad",
"toad",
"mice",
}
customFunctions := template.FuncMap{"unique" : unique}
tmpl, err := template.New("test").Funcs(customFunctions).Parse("{{range $index, $thing := unique $}}The thing is: {{$thing}}\n{{end}}")
Where unique is defined as:
func unique(e []string) []string {
r := []string{}
for _, s := range e {
if !contains(r[:], s) {
r = append(r, s)
}
}
return r
}
func contains(e []string, c string) bool {
for _, s := range e {
if s == c {
return true
}
}
return false
}
Output:
The thing is: mice
The thing is: toad
(It might be better to use a map .. but this gives you the basic idea)
That said - have you considered filtering this outside of the template? That would make things nicer for you.. then you can just iterate over the actual slice within the template.
Working sample: https://play.golang.org/p/L_8t10CpHW
The template can acces a particular custom function http://golang.org/pkg/text/template/#FuncMap. This allows your own logic to be called from within the template.
There is a comprehensive example in the docs which I wont repeat here. The key line is setting up a funcion Map and providing this to the template:
tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText)
Then can be accessed within the template.
{{myCustomFuction .}}
Since now it is established that it will take more go code in the form of a mapped function to achieve, I thought I would share a thought that might get the job done. If you have control of which template that the 'go' program you are not able to modify runs, then you could make several passes. I am also assuming you are on linux. Something like this:
goexe 'first template' // this writes to 'text file'
cat textfile | sort | uniq > 'text file'
goexe 'second template' // your desired output

Iterate through map in Go text template

I have a map of values that looks like this:
vals := map[string]interface{}{"foo": 1, "bar": 2, "baz": 7}
data := map[string]interface{}{"bat": "obj", "values": vals}
What should my template look like to generate the following string (note the correct comma usage)?
SET obj.foo=1, obj.bar=2, obj.baz=7
I started with this as my template:
SET {{range $i, $v := .values}} {{.bat}}.{{$i}}={{$v}},{{end}}
But that just prints out
SET
And even if that did work, the commas would be incorrect. I then tried to use a custom function to format the map, but I couldn't get the template to ever call my function. None of the following seemed to work:
SET {{.MyFunction .values}}
SET {{call .MyFunction .values}}
SET {{call MyFunction .values}}
when MyFunction was defined as:
func MyFunction(data map[string]interface{}) string {
fmt.PrintLn('i was called!')
return "foo"
}
And I'm executing the templates using a helper function that looks like this:
func useTemplate(name string, data interface{}) string {
out := new(bytes.Buffer)
templates[name].Execute(out, data)
return string(out.Bytes())
}
Thanks!
This will get you pretty close:
SET {{range $key, $value := $.values}}{{$.bat}}.{{$key}}={{$value}} {{end}}
rendering as:
SET obj.bar=2 obj.baz=7 obj.foo=1
Unfortunately, I don't think there's any simple way to have the commas added in between the values due to how the range action iterates on maps (there's no numeric index). That said, the template packages were meant to be easily extensible so you can have less logic in your templates and more logic in Go itself, so it's easy enough to code a helper function in Go and make it available to your templates.
If you're happy to go that extra mile, then the template becomes much simpler, and also more efficient. The function can look like this:
func commaJoin(prefix string, m map[string]interface{}) string {
var buf bytes.Buffer
first := true
for k, v := range m {
if !first {
buf.WriteString(", ")
}
first = false
buf.WriteString(prefix)
buf.WriteByte('.')
buf.WriteString(k)
buf.WriteByte('=')
buf.WriteString(fmt.Sprint(v))
}
return buf.String()
}
and your template would look like:
SET {{$.values | commaJoin $.bat}}
Here is a working example with this logic:
http://play.golang.org/p/5lFUpFCzZm

Resources