Constructing HTML output

This section illustrates the use of the html/template package with an example named htmlT.go. It will be presented in six parts. The philosophy of the html/template package is the same with the text/template package. The main difference between these two packages is that the html/template package generates HTML output that is safe against code injection.

Although you can create HTML output with the text/template package-after all, HTML is just plain text-if you want to create HTML output, then you should use the html/template package instead.

For reasons of simplicity, the example presented below will read data from an SQLite database, but you can use any database that you want, provided that you have or you can write the appropriate Go drivers. To make things even easier, the example will populate a database table before reading from it!

The first code portion from htmlT.go follows next:

package main 
 
import ( 
   "database/sql" 
   "fmt" 
   _ "github.com/mattn/go-sqlite3" 
   "html/template" 
   "net/http" 
   "os" 
) 
 
type Entry struct { 
   Number int 
   Double int 
   Square int 
} 
 
var DATA []Entry 
var tFile string 

You can see a new package named net/http in the import block, which is used for creating HTTP servers and clients in Go. You will learn more about network programming in Go and the use of the net and net/http standard Go packages in Chapter 12, The foundations of Network Programming in Go and Chapter 13, Network Programming – Building Servers and Clients.

Apart from net/http, you can also see the definition of the Entry data type that will hold the records read from the SQLite3 table as well as two global variables named DATA and tFile, which hold the data that is going to be passed to the template file and the filename of the template file, respectively.

Also, you can see the use of the https://github.com/mattn/go-sqlite3 package for communicating with the SQLite3 database with the help of the database/sql interface.

The second part of htmlT.go is the following:

func myHandler(w http.ResponseWriter, r *http.Request) { 
   fmt.Printf("Host: %s Path: %s
", r.Host, r.URL.Path) 
   myT := template.Must(template.ParseGlob(tFile)) 
   myT.ExecuteTemplate(w, tFile, DATA) 
} 

The simplicity and the effectiveness of the myHandler() function is phenomenal, especially if you consider the size of the function! The template.ExecuteTemplate() function does all the work for you. Its first parameter is the variable that holds the connection with the HTTP client, its second parameter is the template file that will be used for formatting the data, and its third parameter is the slice of structures with the data that will be processed.

The third code segment from htmlT.go is shown in the following Go code:

func main() { 
   arguments := os.Args 
   if len(arguments) != 3 { 
         fmt.Println("Need Database File + Template File!") 
         return 
   } 
 
   database := arguments[1] 
   tFile = arguments[2] 

The fourth code portion from htmlT.go is where you start dealing with the database:

   db, err := sql.Open("sqlite3", database) 
   if err != nil { 
          fmt.Println(nil) 
          return 
   } 
 
   fmt.Println("Emptying database table.") 
   _, err = db.Exec("DELETE FROM data") 
   if err != nil { 
          fmt.Println(nil) 
          return 
   } 
 
   fmt.Println("Populating", database) 
   stmt, _ := db.Prepare("INSERT INTO data(number, double, square) values(?,?,?)") 
   for i := 20; i < 50; i++ { 
         _, _ = stmt.Exec(i, 2*i, i*i) 
   } 

The sql.Open() function opens the connection with the desired database. With db.Exec(), you can execute database commands without expecting any feedback from them. Also, the db.Prepare() function allows you to execute a database command multiple times by changing only its parameters and calling Exec() afterwards.

The fifth part of htmlT.go contains the following Go code:

   rows, err := db.Query("SELECT * FROM data") 
   if err != nil { 
          fmt.Println(nil) 
          return 
   } 
 
   var n int 
   var d int 
   var s int 
   for rows.Next() { 
         err = rows.Scan(&n, &d, &s) 
         temp := Entry{Number: n, Double: d, Square: s} 
         DATA = append(DATA, temp) 
   } 

In this part of the program, we read the data from the desired table using db.Query() and multiple calls to Next() and Scan(). While reading the data, you put it into a slice of structures and you are done dealing with the database.

The last part of the program is all about setting up the web server, and it contains the following Go code:

   http.HandleFunc("/", myHandler) 
   err = http.ListenAndServe(":8080", nil) 
   if err != nil { 
          fmt.Println(err) 
          return 
   } 
} 

Here, the http.HandleFunc() function tells the web server embedded in the program which URLs will be supported and by which handler function (myHandler()). The current handler supports the / URL, which in Go matches all URLs. This saves you from having to create any extra static or dynamic pages.

The code of the htmlT.go program is divided in two virtual parts. The first part is about getting the data from the database and putting it into a slice of structures, whereas the second part, which is similar to textT.go, is about displaying your data in a web browser.

The two biggest advantages of SQLite are that you do not need to run a server process for the database server and that SQLite databases are stored in self-contained files, which means that single files hold entire SQLite databases.

Note that in order to reduce the Go code and be able to run the htmlT.go program multiple times, you will need to create the database table and the SQLite3 database manually, which is as simple as executing the following commands:

$ sqlite3 htmlT.db
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> CREATE TABLE data (
  ...> number INTEGER PRIMARY KEY,
  ...> double INTEGER,
  ...> square INTEGER );
sqlite> ^D
$ ls -l htmlT.db
-rw-r--r--  1 mtsouk  staff  8192 Dec 26 22:46 htmlT.db  

The first command is executed from the Unix shell, and it is needed for creating the database file. The second command is executed from the SQLite3 shell and has to do with creating a database table named data, which has three fields named number, double, and square, respectively.

Additionally, you are going to need an external template file, which will be named html.gohtml. It is going to be used for the generation of the output of the program.

The first part of html.gohtml is the following:

<!doctype html> 
<html lang="en"> 
<head> 
   <meta charset="UTF-8"> 
         <title>Doing Maths in Go!</title> 
         <style> 
               html { 
                     font-size: 14px; 
               } 
               table, th, td { 
                   border: 2px solid blue; 
               } 
         </style> 
   </head> 
   <body> 

The HTML code that a web browser will read is going to be based on the contents of html.gohtml. This means that you will need to create proper HTML output, hence the preceding HTML code, which also includes some in-line CSS code for formatting the generated HTML table.

The second part of html.gohtml contains the following code:

<table> 
   <thead> 
         <tr> 
              <th>Number</th> 
              <th>Double</th> 
              <th>Square</th> 
         </tr> 
   </thead> 
   <tbody> 
{{ range . }} 
   <tr> 
         <td> {{ .Number }} </td> 
         <td> {{ .Double }} </td> 
         <td> {{ .Square }} </td> 
   </tr> 
{{ end }} 
   </tbody> 
</table> 

As you can see from the preceding code, you still have to use {{ range }} and {{ end }} in order to iterate over the elements of the slice of structures that was passed to template.ExecuteTemplate(). However, this time the html.gohtml template file contains lots of HTML code in order to format the data in the slice of structures better.

The last part of the HTML template file is the following:

</body> 
</html> 

The last part of html.gohtml is mainly used for properly ending the generated HTML code according to the HTML standards.

Before being able to compile and execute htmlT.go, you will need to download the package that will help the Go programming language to communicate with SQLite3. You can do this by executing the following command:

$ go get github.com/mattn/go-sqlite3

As you already know, you can find the source code of the downloaded package inside ~/go/src and its compiled version inside ~/go/pkg/darwin_amd64 if you are on a macOS machine. Otherwise, check the contents of ~/go/pkg to find out your own architecture. Note that the ~ character denotes the home directory of the current user.

Keep in mind that additional Go packages exist that can help you communicate with an SQLite3 database. However, the one used here is the only one that currently supports the database/sql interface.

Executing htmlT.go will produce the kind of output on a web browser that you can see in the following screenshot:

The output of the htmlT.go program

Moreover, htmlT.go will generate the following type of output in your Unix shell, which is mainly debugging information:

$ go run htmlT.go htmlT.db html.gohtml
Emptying database table.
Populating htmlT.db
Host: localhost:8080 Path: /
Host: localhost:8080 Path: /favicon.ico
Host: localhost:8080 Path: /123

If you want to see the HTML output of the program from the Unix shell, you can use the wget(1) utility as follows:

$ wget -qO- http://localhost:8080 
<!doctype html> 
<html lang="en"> 
<head> 
   <meta charset="UTF-8"> 
         <title>Doing Maths in Go!</title> 
         <style> 
               html { 
                      font-size: 14px; 
               } 
               table, th, td { 
                   border: 2px solid blue; 
               } 
         </style> 
   </head> 
   <body> 
 
 
<table> 
   <thead> 
         <tr> 

Both text/template and html/template are powerful packages that can save you a lot of time, so I suggest that you use them when they fit the requirements of your applications.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.148.210