RSS, Atom and general feed parsing and generating

About Feeder

Feeder is a syndication feed library. It presents a general protocol for representation of feed items, as well as a framework to translate these objects from and to external formats. It also implements the RSS 2.0 and Atom formats within this framework.

Translating Feeds

During this document code examples will assume that org.shirakumo.feeder has the local nickname feeder.

In order to parse a feed, simply call parse-feed:

(feeder:parse-feed "<rss><channel><title>Test</title><description>test</description><guid>1</guid><link>http://example.com</link>" T)

It should determine the format used automatically and construct standardised feed instances out of the source. In order to reverse the process and turn a feed into an external format again, simply call serialize-feed:

(feeder:serialize-feed (first *) 'feeder:atom)

Note that while parsing is very lenient, serialising is not, and it will error if certain attributes are missing or malformed. You therefore cannot always round-trip feeds like this.

For xml-formats, the resulting value of serialize-feed will be a plump:node that can be turned into a string with plump:serialize:

(plump:serialize * NIL)

Generating Feeds

In order to generate feeds, you need to translate whatever internal representation of your items you have into entry instances, and then bundle them together into a feed instance. Both feed and entry instances require in the very least an :id, :link, :title, and :summary. The :id can be whatever you want it to be, but it should be an ID that uniquely identifies your item for all time, preferably even globally so. If the link to your item can be used as a unique identifier, you can supply the same link instance to :id and :link. The :summary can either be a string of plain text content, or a plump:node for HTML content.

You should also strongly consider filling in the :authors and :published-on fields, as well as the :content field on entry instances. For the :content, you may supply either plain text or HTML, just as for the :summary.

In order to bundle the entry instances into the feed, simply put them into a list and set that as the feed's :content.

When generating and feed objects and serialising them, the system will check for validity of elements to some limited extent. For instance, required slots that are missing will be reported with errors. Generally whenever an error is signalled, plenty of restarts will be available to help deal with the problem both interactively and in an automated fashion.

Please see the descriptions of feed-condition's subtypes for more information on the error circumstances and possible restarts.

Extending Feeds and Formats

If you need to extend the feed objects or add new feed formats, the functions you should look at are parse-to and serialize-to. In both cases you should add methods to them that specialise on all three arguments, at least one of which must be on a class you control.

Assuming for instance you define an extended person that has an additional location field. Ensuring this field is output into the atom format, you would do something like this:

(defclass extended-person (feeder:person)
  ((location :initarg :location :initform NIL :accessor location)))

(defmethod feeder:serialize-to ((target plump:element) (person extended-person) (format feeder:atom))
  (when (location person)
    (feeder:make-element target :location - (location person))))

When parsing we need to substitute our new class for the instance to use when creating persons. To do so, we require a new format subclass, and a method on instance-for-type:

(defclass extended-format (feeder:atom)

(defmethod feeder:instance-for-type ((type (eql 'person)) (format extended-format))
  (feeder:instance-for-type 'extended-person format))

Finally we can read out the field in a parse-to method:

(defmethod feeder:parse-to ((person extended-person) (node plump:element) (format extended-format))
  (feeder:with-child (child node :location)
    (setf (location person) (feeder:text child))))

Naturally, it is also possible to define entirely new formats that don't necessarily serialise to XML.

System Information

Nicolas Hafner

Definition Index