A social RSS reader built on the AT Protocol. glean.at
glean atproto atmosphere rss feed social app
14
fork

Configure Feed

Select the types of activity you want to include in your feed.

Improve XML parsing

+35 -16
+35 -16
internal/feed/parser.go
··· 1 1 package feed 2 2 3 3 import ( 4 + "bytes" 4 5 "encoding/json" 5 6 "encoding/xml" 6 7 "fmt" ··· 182 183 return result, nil 183 184 } 184 185 185 - func makeXMLDecoder(data []byte) *xml.Decoder { 186 - decoder := xml.NewDecoder(strings.NewReader(string(data))) 186 + func makeXMLDecoder(r io.Reader) *xml.Decoder { 187 + decoder := xml.NewDecoder(r) 187 188 decoder.Strict = false 188 189 decoder.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { 189 190 return htmlcharset.NewReader(input, "text/xml; charset="+charset) ··· 191 192 return decoder 192 193 } 193 194 194 - func parseXMLFeed(data []byte, feedURL string) (*ParseResult, error) { 195 - var rss rssFeed 196 - if err := makeXMLDecoder(data).Decode(&rss); err == nil { 197 - if rss.XMLName.Local == "rss" { 198 - return convertRSS(&rss, feedURL), nil 195 + func detectXMLRoot(data []byte) string { 196 + decoder := makeXMLDecoder(bytes.NewReader(data)) 197 + for { 198 + tok, err := decoder.Token() 199 + if err != nil { 200 + return "" 201 + } 202 + if se, ok := tok.(xml.StartElement); ok { 203 + return se.Name.Local 199 204 } 200 205 } 206 + } 201 207 202 - var atom atomFeed 203 - if err := makeXMLDecoder(data).Decode(&atom); err == nil { 204 - if atom.XMLName.Local == "feed" { 205 - return convertAtom(&atom, feedURL), nil 206 - } 208 + func parseXMLFeed(data []byte, feedURL string) (*ParseResult, error) { 209 + root := detectXMLRoot(data) 210 + if root == "" { 211 + return nil, fmt.Errorf("unable to detect feed format") 207 212 } 208 213 209 - var rdf rdfFeed 210 - if err := makeXMLDecoder(data).Decode(&rdf); err == nil { 211 - if rdf.XMLName.Local == "RDF" { 212 - return convertRDF(&rdf, feedURL), nil 214 + switch root { 215 + case "rss": 216 + var rss rssFeed 217 + if err := makeXMLDecoder(bytes.NewReader(data)).Decode(&rss); err != nil { 218 + return nil, fmt.Errorf("parsing RSS feed: %w", err) 219 + } 220 + return convertRSS(&rss, feedURL), nil 221 + case "feed": 222 + var atom atomFeed 223 + if err := makeXMLDecoder(bytes.NewReader(data)).Decode(&atom); err != nil { 224 + return nil, fmt.Errorf("parsing Atom feed: %w", err) 213 225 } 226 + return convertAtom(&atom, feedURL), nil 227 + case "RDF": 228 + var rdf rdfFeed 229 + if err := makeXMLDecoder(bytes.NewReader(data)).Decode(&rdf); err != nil { 230 + return nil, fmt.Errorf("parsing RDF feed: %w", err) 231 + } 232 + return convertRDF(&rdf, feedURL), nil 214 233 } 215 234 216 235 return nil, fmt.Errorf("unable to detect feed format")