On this page:
2.1 Building feeds
feed-item
feed
2.2 Producing feed XML
express-xml
include-generator?
feed-language
feed-xslt-stylesheet
2.3 Podcasts
episode
podcast
2.4 Feed type predicates
feed-item?
feed?
episode?
podcast?
food?
8.3

2 Library Reference

2.1 Building feeds

Use feed-item and feed to create feeds for web content like blog posts, comments, or even notifications: any content with a timestamp and its own URL.

You have a choice of using RSS or Atom formats, or both. Twenty years ago, holy wars were fought over which format was superior and it was necessary to supply both in order to assure compatibility with the most clients. These days almost every client supports both, so you probably only need to supply one.

You should run all your feeds through the W3C Feed Validator. Please file an issue should you encounter any validation errors in feeds created with Splitflap.

procedure

(feed-item id    
  url    
  title    
  author    
  published    
  updated    
  content    
  [media])  feed-item?
  id : tag-uri?
  url : valid-url-string?
  title : string?
  author : person?
  published : moment?
  updated : moment?
  content : xexpr?
  media : (or/c enclosure? #f) = #f
Returns a #<feed-item> struct for inclusion in a feed. You can inspect its contents with express-xml.

The id argument must be a tag URI (obtain from mint-tag-uri or append-specific).

The title should not contain HTML markup; if it does, it will be escaped, and the raw markup may by shown in applications that use your feed.

The author argument must be a person struct.

The value of updated must be identical to or after published, taking time zone information into account, or an exception is raised. The values for these arguments can be most conveniently supplied by infer-moment, but any moment-producing method will work, such as constructing moments directly, parsing strings with parse-moment, etc.

If content is a tagged X-expression, it will be included as XML-appropriate escaped HTML; if it is a plain string, it will be included as CDATA.

You can optionally use the media argument to supply an enclosure, but if you are generating a feed for a podcast you should consider using episode and podcast instead.

procedure

(feed id site-url name entries)  feed?

  id : tag-uri?
  site-url : valid-url-string?
  name : string?
  entries : (listof feed-item?)
Returns a #<feed> struct. You can inspect its contents with express-xml.

If any of the tag URIs of the entries are tag=? with each other or with the feed id, an exception is raised identifying the first duplicate encountered.

The entries will be sorted in reverse chronological order by their “updated” timestamps. The most recent timestamp is also used as the feed’s own last-updated timestamp.

2.2 Producing feed XML

procedure

(express-xml data 
  dialect 
  [feed-url 
  #:as result-type]) 
  (or/c string? txexpr? document? element?)
  data : food?
  dialect : (or/c 'rss 'atom)
  feed-url : (or/c valid-url-string? #f) = #f
  result-type : (or/c 'xml-string 'xexpr 'xml) = 'xml-string
Returns the expression of data in one of three forms, depending on result-type: a string of XML, a tagged X-expression, or an XML object. In the latter case, the result is a document when data is a feed or a podcast, and an element otherwise.

The dialect argument is ignored when data is an episode or a podcast, since Apple’s Podcast feed requirements stipulate the use of RSS 2.0 for podcast feeds.

The feed-url argument must be supplied as a valid URL string when data is a feed or a podcast; this should be the URL where the feed itself will be located. It is not a required argument when data is any other type, and in those cases it will be ignored if supplied.

For complete feeds (e.g., when data is a feed or podcast) the output can be further affected by other parameters. View their documentation for more information.

Examples:
> (define item
    (feed-item (mint-tag-uri "rclib.example.com" "2012-06" "blog:example-post")
               "http://rclib.example.com"
               "Example"
               (person "Marion Paroo" "marion@rclib.example.com")
               (infer-moment "2013-04-13 08:45")
               (infer-moment "2013-04-14")
               '(article (p "Etc…"))))
> (display (express-xml item 'atom #f))

<entry>

  <title type="text">Example</title>

  <link rel="alternate" href="http://rclib.example.com" />

  <updated>2013-04-14T00:00:00Z</updated>

  <published>2013-04-13T08:45:00Z</published>

  <author>

    <name>Marion Paroo</name>

    <email>marion@rclib.example.com</email>

  </author>

  <id>tag:rclib.example.com,2012-06:blog:example-post</id>

  <content type="html">&lt;article&gt;&lt;p&gt;Etc…&lt;/p&gt;&lt;/article&gt;</content>

</entry>

> (express-xml item 'atom #:as 'xexpr)

'(entry

  (title ((type "text")) "Example")

  (link ((rel "alternate") (href "http://rclib.example.com")))

  (updated "2013-04-14T00:00:00Z")

  (published "2013-04-13T08:45:00Z")

  (author (name "Marion Paroo") (email "marion@rclib.example.com"))

  (id "tag:rclib.example.com,2012-06:blog:example-post")

  (content ((type "html")) "<article><p>Etc…</p></article>"))

parameter

(include-generator?)  boolean?

(include-generator? incl?)  void?
  incl? : boolean?
 = #t
When set to #t, express-xml will include a generator element in the feed generated for a feed or podcast, naming Racket vN.n [cs/3m] / splitflap vN.n as the generator of the feed.

parameter

(feed-language)  (or/c iso-639-language-code? #f)

(feed-language lang)  void?
  lang : (or/c iso-639-language-code? #f)
 = #f
A parameter that, when not set to #f, is used by express-xml as the language for a feed or podcast in place of system-language.

parameter

(feed-xslt-stylesheet)  (or/c url? non-empty-string? #f)

(feed-xslt-stylesheet path)  void?
  path : (or/c url? non-empty-string? #f)
 = #f
If this parameter is not #f, express-xml will use its value as the path to an XSLT stylesheet in the prolog of the XML document produced for a feed or podcast.

Generally, the XSLT file must be served from the same domain as the feed itself, otherwise the styling will not be applied.

Stylesheets can solve the problem of feeds looking and behaving in unfriendly ways when accessed directly in a web browser. See this Github issue for examples of people who have used XSLT stylesheets to add informative links and a welcoming layout to their feeds.

2.3 Podcasts

Splitflap provides some special data types for podcast feeds: episode and podcast. These are patterned after Apple’s Podcast feed requirements since those serve as a kind of de facto standard for this application.

procedure

(episode id    
  url    
  title    
  author    
  published    
  updated    
  content    
  media    
  [#:duration duration    
  #:image-url image-url    
  #:explicit? explicit    
  #:episode-num ep-num    
  #:season-num s-num    
  #:type type    
  #:block? block])  episode?
  id : tag-uri?
  url : valid-url-string?
  title : string?
  author : person?
  published : moment?
  updated : moment?
  content : xexpr?
  media : enclosure?
  duration : (or/c exact-nonnegative-integer? #f) = #f
  image-url : (or/c valid-url-string? #f) = #f
  explicit : any/c = null
  ep-num : (or/c exact-nonnegative-integer? #f) = #f
  s-num : (or/c exact-nonnegative-integer? #f) = #f
  type : (or/c 'trailer 'full 'bonus #f) = #f
  block : any/c = #f
Returns an #<episode> struct, which is required for podcasts in the same way that feed-items are required for feeds. You can inspect its contents with express-xml.

The value of updated must be identical to or after published, taking time zone information into account, or an exception is raised. The values for these arguments can be most conveniently supplied by infer-moment, but any moment-producing method will work, such as constructing moments directly, parsing strings with parse-moment, etc.

If content is a tagged X-expression, it will be included as escaped HTML; if it is a plain string, it will be included as CDATA.

Below are further notes about particular elements supplied to episode. The colored passages indicate things which are required by Apple for inclusion in the Apple Podcasts directory but which are not validated by Splitflap. (See Apple’s Podcast feed requirements.)

procedure

(podcast id    
  site-url    
  name    
  episodes    
  category    
  image-url    
  owner    
  #:explicit? explicit    
  [#:type type    
  #:block? block    
  #:complete? complete    
  #:new-feed-url new-url])  podcast?
  id : tag-uri?
  site-url : valid-url-string?
  name : string?
  episodes : (listof episode?)
  category : (or/c string? (list/c string? string?))
  image-url : valid-url-string?
  owner : person?
  explicit : any/c
  type : (or/c 'serial 'episodic #f) = #f
  block : any/c = #f
  complete : any/c = #f
  new-url : (or/c valid-url-string? #f) = #f
Returns a #<podcast> struct, which can be converted into a feed with express-xml.

If any of the tag URIs of the episodes are tag=? with each other or with the podcast feed id, an exception is raised identifying the first duplicate encountered.

Below are some notes about particular elements supplied to podcast. The colored passages indicate things which are required by Apple for inclusion in the Apple Podcasts directory but which are not validated by Splitflap. (See Apple’s Podcast feed requirements.)

2.4 Feed type predicates

procedure

(feed-item? v)  boolean?

  v : any/c
Returns #t if v is a feed-item struct, #f otherwise.

procedure

(feed? v)  boolean?

  v : any/c
Returns #t if v is a feed struct, #f otherwise.

procedure

(episode? v)  boolean?

  v : any/c
Returns #t if v is an episode struct, #f otherwise.

procedure

(podcast? v)  boolean?

  v : any/c
Returns #t if v is a podcast struct, #f otherwise.

procedure

(food? v)  boolean?

  v : any/c
Returns #t when v is one of the struct types that implements the generic express-xml function: enclosure, feed-item, feed, episode, or podcast; #f otherwise