99 "encoding/xml"
1010 "fmt"
1111 "io"
12+ "strings"
1213 "time"
1314)
1415
@@ -19,28 +20,26 @@ type RssFeedExtXml struct {
1920 ContentNamespace string `xml:"xmlns:content,attr"`
2021 CustomNamespaces []xml.Attr `xml:",attr"`
2122 Channel * RssFeedExt
22- }
23-
24- type RssContentExt struct {
25- XMLName xml.Name `xml:"content:encoded"`
26- Content string `xml:",cdata"`
23+ Extensions []Extension `xml:",any"`
2724}
2825
2926type RssImageExt struct {
30- XMLName xml.Name `xml:"image"`
31- Url string `xml:"url"`
32- Title string `xml:"title"`
33- Link string `xml:"link"`
34- Width int `xml:"width,omitempty"`
35- Height int `xml:"height,omitempty"`
27+ XMLName xml.Name `xml:"image"`
28+ Url string `xml:"url"`
29+ Title string `xml:"title"`
30+ Link string `xml:"link"`
31+ Width int `xml:"width,omitempty"`
32+ Height int `xml:"height,omitempty"`
33+ Extensions []Extension `xml:",any"`
3634}
3735
3836type RssTextInputExt struct {
39- XMLName xml.Name `xml:"textInput"`
40- Title string `xml:"title"`
41- Description string `xml:"description"`
42- Name string `xml:"name"`
43- Link string `xml:"link"`
37+ XMLName xml.Name `xml:"textInput"`
38+ Title string `xml:"title"`
39+ Description string `xml:"description"`
40+ Name string `xml:"name"`
41+ Link string `xml:"link"`
42+ Extensions []Extension `xml:",any"`
4443}
4544
4645type RssFeedExt struct {
@@ -65,36 +64,23 @@ type RssFeedExt struct {
6564 Image * RssImageExt
6665 TextInput * RssTextInputExt
6766 Items []* RssItemExt `xml:"item"`
67+ Extensions []Extension `xml:",any"`
6868}
6969
7070type RssItemExt struct {
7171 XMLName xml.Name `xml:"item"`
7272 Title string `xml:"title"` // required
7373 Link string `xml:"link"` // required
7474 Description string `xml:"description"` // required
75- Content * RssContentExt
75+ Content * RssContent
7676 Author string `xml:"author,omitempty"`
7777 Category string `xml:"category,omitempty"`
7878 Comments string `xml:"comments,omitempty"`
79- Enclosure * RssEnclosureExt
80- Guid * RssGuidExt // Id used
79+ Enclosure * RssEnclosure
80+ Guid * RssGuid // Id used
8181 PubDate string `xml:"pubDate,omitempty"` // created or updated
8282 Source string `xml:"source,omitempty"`
83- }
84-
85- type RssEnclosureExt struct {
86- //RSS 2.0 <enclosure url="http://example.com/file.mp3" length="123456789" type="audio/mpeg" />
87- XMLName xml.Name `xml:"enclosure"`
88- Url string `xml:"url,attr"`
89- Length string `xml:"length,attr"`
90- Type string `xml:"type,attr"`
91- }
92-
93- type RssGuidExt struct {
94- //RSS 2.0 <guid isPermaLink="true">http://inessential.com/2002/09/01.php#a2</guid>
95- XMLName xml.Name `xml:"guid"`
96- Id string `xml:",chardata"`
97- IsPermaLink string `xml:"isPermaLink,attr,omitempty"` // "true", "false", or an empty string
83+ Extensions []Extension `xml:",any"`
9884}
9985
10086type RssExt struct {
@@ -109,21 +95,21 @@ func newRssItemExt(i *Item) *RssItemExt {
10995 PubDate : anyTimeFormat (time .RFC1123Z , i .Created , i .Updated ),
11096 }
11197 if i .Id != "" {
112- item .Guid = & RssGuidExt {Id : i .Id , IsPermaLink : i .IsPermaLink }
98+ item .Guid = & RssGuid {Id : i .Id , IsPermaLink : i .IsPermaLink }
11399 }
114100 if i .Link != nil {
115101 item .Link = i .Link .Href
116102 }
117103 if len (i .Content ) > 0 {
118- item .Content = & RssContentExt {Content : i .Content }
104+ item .Content = & RssContent {Content : i .Content }
119105 }
120106 if i .Source != nil {
121107 item .Source = i .Source .Href
122108 }
123109
124110 // Define a closure
125111 if i .Enclosure != nil && i .Enclosure .Type != "" && i .Enclosure .Length != "" {
126- item .Enclosure = & RssEnclosureExt {Url : i .Enclosure .Url , Type : i .Enclosure .Type , Length : i .Enclosure .Length }
112+ item .Enclosure = & RssEnclosure {Url : i .Enclosure .Url , Type : i .Enclosure .Type , Length : i .Enclosure .Length }
127113 }
128114
129115 if i .Author != nil {
@@ -182,10 +168,6 @@ func (r *RssFeedExt) FeedXml() interface{} {
182168 Version : "2.0" ,
183169 Channel : r ,
184170 ContentNamespace : "http://purl.org/rss/1.0/modules/content/" ,
185- CustomNamespaces : []xml.Attr {
186- // TODO: we need more here ...
187- {Name : xml.Name {Local : "xmlns:content" }, Value : "http://purl.org/rss/1.0/modules/content/" },
188- },
189171 }
190172}
191173
@@ -231,3 +213,34 @@ func UnmarshalRssFeedExt(data []byte) (*RssFeedExtXml, error) {
231213 }
232214 return feed , nil
233215}
216+
217+ type Extension struct {
218+ XMLName xml.Name
219+ Attrs []xml.Attr `xml:",any,attr"`
220+ Children []Extension `xml:",any"`
221+ Value string `xml:",chardata"`
222+ }
223+
224+ func (e * Extension ) UnmarshalXML (d * xml.Decoder , start xml.StartElement ) error {
225+ // Filter xmlns attributes
226+ var filteredAttrs []xml.Attr
227+ for _ , attr := range start .Attr {
228+ if attr .Name .Space == "xmlns" || attr .Name .Local == "xmlns" {
229+ continue
230+ }
231+ filteredAttrs = append (filteredAttrs , attr )
232+ }
233+ // Update start.Attr so DecodeElement uses the filtered list
234+ start .Attr = filteredAttrs
235+
236+ type extensionAlias Extension
237+ var v extensionAlias
238+
239+ if err := d .DecodeElement (& v , & start ); err != nil {
240+ return err
241+ }
242+
243+ * e = Extension (v )
244+ e .Value = strings .TrimSpace (e .Value )
245+ return nil
246+ }
0 commit comments