package main import ( "encoding/csv" "html/template" "io" "log" "net/http" "os" "strconv" ) var COLUMNS []string type FinancialData struct { Date string Open, High, Low, Close, Adj_Close, Volume float64 } type TplData struct { Columns []string Rows []FinancialData } func printHTML(tpl *template.Template, data []FinancialData, out io.Writer) { tplData := TplData{ COLUMNS, data, } err := tpl.ExecuteTemplate(out, "tpl.html", tplData) if err != nil { panic(err) } } func readCsvLine(line []string) *FinancialData { data := new(FinancialData) for i, col := range line { switch COLUMNS[i] { case "Date": data.Date = col case "Open": data.Open = toFloat(col) case "High": data.High = toFloat(col) case "Low": data.Low = toFloat(col) case "Close": data.Close = toFloat(col) case "Adj Close": data.Adj_Close = toFloat(col) case "Volume": data.Volume = toFloat(col) } } return data } func toFloat(v string) float64 { f, err := strconv.ParseFloat(v, 64) if err != nil { log.Fatalln(err) } return f } func readCsvHeader(line []string) { for _, col := range line { COLUMNS = append(COLUMNS, col) } } func readCsv(in io.Reader) []FinancialData { data := []FinancialData{} csvReader := csv.NewReader(in) for { line, err := csvReader.Read() if err == io.EOF { break } else if err != nil { log.Fatal(err) } if len(COLUMNS) == 0 { readCsvHeader(line) } else { data = append(data, *readCsvLine(line)) } } return data } func main() { if len(os.Args) < 2 { log.Fatalln("Usage go-financial ") } // read input csv, err := os.Open(os.Args[1]) if err != nil { log.Fatalln("Error reading file", err) } defer csv.Close() // parse data data := readCsv(csv) tpl, err := template.New("").Funcs(template.FuncMap{ "class": func(index int) string { if index%2 == 0 { return "even" } return "odd" }, }).ParseFiles("tpl.html", "script.js") if err != nil { panic(err) } http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) { printHTML(tpl, data, res) }) http.ListenAndServe(":9000", nil) }