Skip to content

Instantly share code, notes, and snippets.

@hollingberry
Last active August 29, 2015 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hollingberry/0f1a1bac8c608f4ba1df to your computer and use it in GitHub Desktop.
Save hollingberry/0f1a1bac8c608f4ba1df to your computer and use it in GitHub Desktop.
package main
import (
"encoding/xml"
"fmt"
"io"
"strings"
)
type Student struct {
Id string
FirstName string
MiddleName string
LastName string
}
type Gradebook struct {
Files Stack
Decoder *xml.Decoder
}
type Record struct {
Code string `xml:"Code,attr"`
Items []Item `xml:"Item"`
}
type Item struct {
Name string `xml:"Name,attr"`
Value string `xml:",chardata"`
}
func NewGradebookWithReader(r io.Reader) *Gradebook {
d := xml.NewDecoder(r)
return NewGradebookWithDecoder(d)
}
func NewGradebookWithDecoder(d *xml.Decoder) *Gradebook {
return &Gradebook{Decoder: d}
}
func (gb *Gradebook) Records() []Record {
var records []Record
for {
t, _ := gb.Decoder.Token()
if t == nil {
break
}
switch elem := t.(type) {
case xml.StartElement:
switch elem.Name.Local {
case "File":
gb.Files.Push(attr(elem, "ID"))
case "Record":
if gb.Files.Peek() == "281" {
var r Record
gb.Decoder.DecodeElement(&r, &elem)
records = append(records, r)
}
}
case xml.EndElement:
switch elem.Name.Local {
case "File":
gb.Files.Pop()
}
}
}
return records
}
func (gb *Gradebook) Students() []Student {
var students []Student
for _, r := range gb.Records() {
students = append(students, r.Student())
}
return students
}
func (r Record) Student() Student {
s := Student{}
s.Id = r.Code
s.FirstName = item(r, "Name:First")
s.MiddleName = item(r, "Name:Middle")
s.LastName = item(r, "Name:Last")
return s
}
type Stack []string
func (s Stack) Empty() bool {
return len(s) == 0
}
func (s Stack) Peek() string {
return s[len(s)-1]
}
func (s *Stack) Push(v string) {
(*s) = append((*s), v)
}
func (s *Stack) Pop() string {
top := (*s)[len(*s)-1]
(*s) = (*s)[:len(*s)-1]
return top
}
func item(r Record, name string) string {
for _, item := range r.Items {
if item.Name == name {
return item.Value
}
}
return ""
}
func attr(elem xml.StartElement, name string) string {
for _, attr := range elem.Attr {
if attr.Name.Local == name {
return attr.Value
}
}
return ""
}
@hollingberry
Copy link
Author

Okay, this runs through 11MB in about 1.145s.

@hollingberry
Copy link
Author

If there's 1.7 GB of data, we can estimate about (1.7 GB * 1024 MB/GB) / (11 MB / 1.145 s) = 181.2 seconds. Not particularly fast. Also not concurrent or optimized in any way.

@hollingberry
Copy link
Author

Yeah this is like 3x as slow as the Ruby version (with Ox). Jeez... somethin’ is up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment