package rfc import ( "bytes" "encoding/xml" "fmt" "io" "io/ioutil" "net/http" ) const ( RFCIndex = "rfc-index.xml" RFCURL = "http://www.rfc-editor.org/in-notes/" + RFCIndex ) type Index struct { Entries []Entry `xml:"rfc-entry"` } type Entry struct { DocID string `xml:"doc-id"` Title string `xml:"title"` Authors []string `xml:"author>name"` Month string `xml:"date>month"` Year string `xml:"date>year"` Format string `xml:"format>file-format"` Chars int `xml:"format>char-count"` Pages int `xml:"format>page-count"` Keywords []string `xml:"keywords>kw"` Abstract string `xml:"abstract>p"` Draft string `xml:"draft"` Notes string `xml:"notes"` Obsoletes []string `xml:"obsoletes>doc-id"` ObsoletedBy []string `xml:"obsoleted-by>doc-id"` Updates []string `xml:"updates>doc-id"` UpdatedBy []string `xml:"updated-by>doc-id"` IsAlso []string `xml:"is-also>doc-id"` SeeAlso []string `xml:"see-also>doc-id"` CurrentStatus string `xml:"current-status"` PublicationStatus string `xml:"publication-status"` Stream string `xml:"stream"` Area string `xml:"area"` Acronym string `xml:"wg_acronym"` Errata string `xml:"errata-url"` Doi string `xml:"doi"` } func Decode(r io.Reader) ([]Entry, error) { i := Index{} err := xml.NewDecoder(r).Decode(&i) if err != nil { return nil, err } return i.Entries, nil } func Fetch() ([]byte, error) { resp, err := http.Get(RFCURL) if err != nil { return nil, err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } return body, ioutil.WriteFile(RFCIndex, body, 0644) } func Open() (io.Reader, error) { body, err := ioutil.ReadFile(RFCIndex) if err != nil { body, err = Fetch() if err != nil { return nil, err } } return bytes.NewReader(body), nil } func refs(prefix string, s []string) (ret string) { if s != nil { ret = fmt.Sprint(", ", prefix, ": ") for i, v := range s { if i != 0 { ret += ", " } ret += fmt.Sprint(v) } } return } func (e Entry) String() string { ret := fmt.Sprint(e.DocID, ": ", e.Title) ret += fmt.Sprint(refs("updates", e.Updates)) ret += fmt.Sprint(refs("obsoletes", e.Obsoletes)) ret += fmt.Sprint(refs("updated by", e.UpdatedBy)) ret += fmt.Sprint(refs("obsoleted by", e.ObsoletedBy)) ret += fmt.Sprint(refs("is also", e.IsAlso)) ret += fmt.Sprint(refs("see also", e.SeeAlso)) return ret } func (e Entry) ID() (id int) { fmt.Sscanf(e.DocID, "RFC%d", &id) return }