Simple Sharing Extensions for RSS and OPML

Simple Sharing Extensions for RSS and OPML

This specification was previously published on the XML Developer Center.

Version: 0.91
Editors: Jack Ozzie, George Moromisato, and Paresh Suthar, Microsoft Corporation
Updated: 01/12/06

Contents:

  • 1 Overview 
    • 1.1 Namespaces and Version 
    • 1.2 Notational Conventions 
    • 1.3 Usage Model 
  • 2 Extensions 
    • 2.1 <sx:sharing> element within RSS <channel> or OPML <head> 
    • 2.2 <sx:related> element within <sx:sharing> 
    • 2.3 <sx:sync> element within RSS <item> or OPML <outline> 
    • 2.4 <sx:history> element within <sx:sync> 
    • 2.5 <sx:update> element within <sx:history> 
  • 3 Required Behavior for Change Processing 
    • 3.1 Unordered Behavior 
    • 3.2 Ordered Behavior 
  • 4 Required Behavior for Maintaining History 
    • 4.1 Creation Behavior 
    • 4.2 Update Behavior 
    • 4.3 Global Consistency Assurance 
    • 4.4 Incorporating History 
  • 5 Optional Conflict Resolution Behavior 
    • 5.1 <sx:conflicts> element within <sx:sync> 
    • 5.2 <sx:conflict> element within <sx:conflicts> 
  • 6 Licensing Information 

1 Overview

Simple Sharing extends the Really Simple Syndication (RSS) 2.0 and Outline Processor Markup Language (OPML) 1.0 specifications:

The objective of Simple Sharing Extensions (SSE) is to define the minimum extensions necessary to enable loosely-cooperating apps

  1. to use RSS as the basis for item sharing– that is, the bi-directional, asynchronous replication of new and changed items amongst two or more cross-subscribed feeds, and/or
  2. to use OPML as the basis for outline sharing– that is, the bi-directional, asynchronous replication of outlines, such as RSS aggregators' subscription lists.

1.1 Namespaces and Version

The XML namespace URI for the XML data format described in this specification is:

https://www.microsoft.com/schemas/rss/sse

In this spec, the prefix "sx:" is used for the namespace URI identified above. For example:

<rss version=2.0
xmlns:sx="https://www.microsoft.com/schemas/rss/sse">

1.2 Notational Conventions

In this document, the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as described in RFC 2119.

The term item denotes a typed data entity and the basic unit of sharing and synchronization.

The term endpoint denotes an entity that participates in the synchronization of shared items with other endpoints. An endpoint can act as a publisher, a subscriber or both.

An endpoint's item set is a complete set of related items as determined by the endpoint.

A feed is an addressable collection of items in a endpoint's item set. The feed may be partial (only the items that have changed within a given time window) or complete (all of the items in the endpoint's item set are contained in the feed as of its publishing).

A subscription is a unidirectional relationship between two endpoints where one endpoint acting as a subscriber pulls feeds from the other endpoint, which acts as a publisher.

The term updated is used to include items created, changed or deleted.

All date-time values MUST be expressed as GMT and MUST conform to the Date and Time specification of RFC 822, except using 4 digit years (consistent with RSS 2.0 specification).

All endpoint identifiers MUST conform to the syntax for Namespace Specific Strings (the NSS portion of a URN) in RFC 2141.

1.3 Usage Model

Imagine two loosely coupled endpoints, A and B, that wish to share and co-edit a set of independent items in an RSS feed. The two endpoints can use RSS+SSE to replicate the set. The process would look like this:

  1. Endpoint A maintains an item set. Endpoint A publishes the set as a feed conforming to the RSS+SSE format. Let's call this feed-A.
  2. Endpoint B also maintains an item set. Endpoint B subscribes to feed-A and incorporates the items into its own set.
  3. Endpoint B publishes its own set (including items it got from A) as a feed conforming to RSS+SSE. Let's call this feed-B.
  4. Endpoint A subscribes to feed-B and incorporates items from endpoint B into its own set. In effect, endpoints A and B mutually publish/subscribe to each other's feeds.
  5. When endpoint A adds or changes an item, that update is reflected in feed-A and endpoint B receives the change when it reads the feed.
  6. Similarly, when endpoint B adds or changes an item, the update is published in feed-B and endpoint A receives the change.

The extensions described in SSE enable feed readers and publishers to generate and process incoming item changes in a manner that enables consistency to be achieved. In order to accomplish this, SSE introduces concepts such as per-item change history (to manage item versions and update conflicts) and tombstones (to propagate deletions, and un-deletions).

2 Extensions

2.1 <sx:sharing> element within RSS <channel> or OPML <head>

Attributes Description
since An optional date-time attribute. All items updated on or after this date-time are included in the feed. If not present or null, the "beginning of time" is assumed and the feed contains the node's complete item set as of the until date-time.
until An optional date-time attribute. Items updated after this date are not included in the feed. The publisher MUST guarantee that the value of until will increase if any items in the feed are updated. If this attribute is omitted or blank, the subscriber cannot make assumptions about when the feed was updated.
version A required, string attribute.The version of the SSE specification that was used to generate the content.
window An optional, integer attribute. This is an integer value (in days) expressing the size of the window of change history kept by the publisher. Subscribers MAY use this value to determine the frequency with which they should read a feed.

The sx:sharing element is optional, in which case defaults are assumed. When sx:sharing is present, it contains all of the top-level properties required by SSE, described in the following section.

2.2 <sx:related> element within <sx:sharing>

Attributes Description
link A required, URL attribute. The URL for related feeds.
title An optional, string attribute. The name or description of the related feed.
type A required, string attribute. This attribute can have one of the following values:
  • "complete" if the link points to file containing the complete collection of items for this feed.
  • "aggregated" if the link points to a feed whose contents are being incorporated into this feed by the publisher.
since An optional, date-time attribute. This is the starting point of the related feed. If this attribute is omitted or blank, it is assumed that this is a complete feed.
until An optional, date-time attribute. This is the ending point of a feed.

The sx:related element is optional, but when present contains information about related feeds.

2.2.1 INCREMENTAL FEEDS and COMPLETE FEEDS

Publishers will generally include, in a feed, only the most recent modifications, additions, and deletions within some reasonable time window. These feeds are referred to herein as partial feeds, whereas feeds containing the complete set of items are referred to as complete feeds.

In the feed sharing context, new subscribers will need to initially copy a complete set of items from a publisher before being in a position to process incremental updates. As such, this spec provides for the ability for the latter feed to reference the complete feed. By placing the link to this feed in the channel descriptor, only the partial feed URL need to be distributed to potential subscribers.

2.2.2 AGGREGATED FEEDS

In the case where a publisher has aggregated information from other feeds into a larger work, it can be useful for subscribers to see more detailed information about the other source feeds. In the case of feed sharing as envisioned by this specification, this feature can also be used to notify subscribing feeds of the feeds of other participants which they might also wish to subscribe to.

EXAMPLE
<channel>
<sx:sharing
since="Tue, 1 Nov 2004 09:43:33 GMT"
until="Fri, 1 Mar 2005 09:43:33 GMT"
version="0.91" >
<sx:related link="http://x.com/all.xml" type="complete" />
<sx:related link="http://y.net/B.xml" type="aggregated" 
title="Family Contacts (Dad's Copy)" />
<sx:related link="http://y.net/C.xml" type="aggregated" 
title="Family Contacts (Suzy's Copy)" />
</sx:sharing>
...
</channel>

2.3 <sx:sync> element within RSS <item> or OPML <outline>

Attributes Description
id A required, string attribute. This is the identifier for the item. The ID MUST be globally unique within the feed and it MUST be identical across feeds if an item is being shared or replicated as part of multiple distinct independent feeds.

The ID is assigned by the creator of the item, and MUST NOT be changed by subsequent publishers. Applications will collate and compare these identifiers, therefore they MUST conform to the syntax for Namespace Specific Strings (the NSS portion of a URN) in RFC 2141.

version A required, integer attribute. This is the modification sequence number of the item, starting at 1 and incrementing by 1 indefinitely for each subsequent modification.
deleted An optional, Boolean attribute. If present and its value is "true" (lower-case), it indicates that the item has been deleted and this is a tombstone. If not present, or if present with value of "false" or if empty (""), then the item is not deleted. All other values are invalid.
conflict An optional, Boolean attribute. If present and its value is "true" (lower-case), it indicates there was an update conflict detected when processing an update of this item, and it should potentially be examined by the user. If not present, or present with value of "false" or if empty (""), then no conflict has been detected. All other values are invalid.

The most important extension described in this spec is the sx:sync element, which contains the information required for synchronization. This element is a child of the item or outline element. This is a REQUIRED element of all items in all feeds wishing to participate in SSE-based replication.

2.4 <sx:history> element within <sx:sync>

Attributes Description
when A date-time attribute. This is the date-time when the most recent modification took place. If this attribute is omitted the value defaults to the earliest time representable in RFC 822.

Note: Either or both of the when or by attributes MUST be present; it is invalid to have neither.

by A string attribute. A text attribute identifying the unique endpoint that made the most recent modification. This SHOULD be some combination of user and device (so that a given user can edit a feed on multiple devices). This attribute is used programmatically to break ties in case two changes happened at the same time (within the same second). If this attribute is omitted the value defaults to the empty string (which MUST be less than all other values for purposes of collation).

Note: Either or both of the when or by MUST be present; it is invalid to have neither.

The sx:sync element MUST contain a sx:history element that contains the chronological history for the item.

2.5 <sx:update> element within <sx:history>

Attributes Description
when A date-time attribute. This is the date-time when the modification took place. If this attribute is omitted the value defaults to the earliest time representable in RFC 822.

Note: Either or both of the when or by attributes MUST be present; it is invalid to have neither.

by A string attribute. A text attribute identifying the unique endpoint that made a modification. This SHOULD be some combination of user and device (so that a given user can edit a feed on multiple devices). This attribute is used programmatically to break ties in case two changes happened at the same time (within the same second). If this attribute is omitted the value defaults to the empty string (which MUST be less than all other values for purposes of collation).

Note: Either or both of the when or by MUST be present; it is invalid to have neither.

The sx:history element MAY contain one or more sx:update sub-elements, each of which represents a distinct update to the item.

3 Required Behavior for Change Processing

To assure consistency, incoming (subscribed) feed items are processed one at a time, and are compared with already-known items whose state is maintained locally (and potentially published to others on an outbound feed). When merging such changed items or outline elements into a the local feed, processing behavior differs for "unordered" vs. "ordered" feeds.

3.1 Unordered Behavior

In unordered feeds, changes are processed one at a time, and the local copy of an item is generally looked-up by using the id attribute from the sx:sync element of the incoming item. The two are then compared, and a "winner" and a "loser" are declared, and the local item is updated appropriately.

3.2 Ordered Behavior

In ordered feeds, changes MUST be processed such that the order of items is preserved. When the position of an item is modified, the publishers and subscribers MUST follow these rules:

  • When an item is moved (in order or in hierarchy) the publisher MUST ensure that the item is updated (as described in section 4.2). The subscriber MUST incorporate the new position for the item.
  • If two or more items are moved or added to the same location by different endpoints, the subscriber MUST order the elements alphabetically (ascending) by using a text collation on the id attribute of the sx:sync element.
  • In a hierarchy (such as OPML), the winner stays with its parent regardless of any changes to the position of the parent. Note that this is not the same as preserving the winner's absolute place in the hierarchy.

4 Required Behavior for Maintaining History

4.1 Creation Behavior

When creating a new item as the result of a local user operation, endpoints MUST follow this algorithm:

  1. Create an sx:sync element with a version of "1" and a unique id (see section 2.3).
  2. Create an update history record as follows:
    1. Add an sx:history element as a child of sx:sync.
    2. Do one or both of:
      • Set the when attribute in sx:history to the current date-time.
      • Set the by attribute in sx:history to this endpoint's identifier.

EXAMPLE

Here is what an item would look like after being created:

<item>
<description>This is a test item</description>
<sx:sync id="0a7903db47fb0ae8" version="1">
<sx:history when="Sat, 21 May 2005 09:43:33 GMT" by="REO1750"/>
</sx:sync>
</item>

4.2 Update Behavior

When incorporating endpoints' item updates from other feeds into the current feed, items are copied leaving the sx:sync element completely intact. However, when creating, updating or deleting an item as the result of a local user operation, endpoints MUST follow this algorithm:

  1. Increment the version attribute of the sx:sync element by 1.
  2. Update the update history records as follows:
    1. In the sx:history element, insert a new sx:update sub-element as the first child of the sx:history element.
    2. On that new sx:update element, set the when and by attributes to the values in the sx:history element.
    3. The application MAY truncate the set of sx:update elements (always deleting from the bottom up) to any number (including 0).
    4. Set the when attribute on the sx:history element to the current date-time.
    5. Set the by attribute on the sx:history element to this endpoint.
  3. If this is a deletion, set the deleted attribute on sx:sync to true, else set it to false or remove it.
  4. Remove the conflict attribute from the sx:sync element, and remove the sx:conflicts sub-element from the sx:sync element, if present.

EXAMPLES

Here is what the same item in the above example would look like after having been updated three more times in sequence, once a day, by the same endpoint:

<item>
<description>This is a test item</description>
<sx:sync id="0a7903db47fb0ae8" version="4">
<sx:history when="Tue, 24 May 2005 09:43:33 GMT" by="REO1750">
<sx:update when="Mon, 23 May 2005 09:43:33 GMT" by="REO1750" />
<sx:update when="Sun, 22 May 2005 09:43:33 GMT" by="REO1750" />
<sx:update when="Sat, 21 May 2005 09:43:33 GMT" by="REO1750" />
</sx:history>
</sx:sync>
</item>

Here is what the same item would look like after having been updated two more times in sequence, once a day, by the same endpoint, but after the particular implementation only maintains a limited number of versions (4):

<item>
<description>This is a test item</description>
<sx:sync id="0a7903db47fb0ae8" version="6">
<sx:history when="Thu, 26 May 2005 09:43:33 GMT" by="REO1750">
<sx:update when="Wed, 25 May 2005 09:43:33 GMT" by="REO1750" />
<sx:update when="Tue, 24 May 2005 09:43:33 GMT" by="REO1750" />
<sx:update when="Mon, 23 May 2005 09:43:33 GMT" by="REO1750" />
</sx:history>
</sx:sync>
</item>

4.3 Global Consistency Assurance

When a subscriber reads a feed, it MUST determine if others' modifications to items are more recent than the subscriber's own modifications. For example, imagine A, B and C mutually publish/subscribe, and all three modify item #1. When each reads the others' feed, all implementations MUST detect which modification will "win" and which will "lose," consistently.

Feed items are processed one at a time, and are compared with already-known items whose state is maintained locally (and potentially published to others on an outbound feed).

4.4 Incorporating History

To ensure global consistency, all implementations MUST use this algorithm when comparing an incoming item from a publisher:

  1. When comparing the incoming item to its corresponding local item, the "winner" is determined by a collation using comparison of these four keys, in order:
    1. the version attribute of the sx:sync element (larger version number wins)
    2. the when attribute of the sx:history element (later date/time wins; if it is present on one and not present on the other, present wins)
    3. the by attribute of the sx:history element ("greater" normalized text wins; if it is present on one and not present on the other, present wins)
  2. If the collation results in equality on all tests, the two items are deemed to be identical and no action is required on this item.
  3. Now that a "winner" and a "loser" have been declared, one MUST detect to see if this was a normal sequence of edits, of if the endpoints separately edited the same version of the same item and "stepped on" each others' changes. This is called conflict detection.

4.4.1 Conflict Detection

In order to detect conflicts, endpoints MUST follow this algorithm on the modification history of two updated items:

  1. If there is an sx:history element:
    1. Let n equal the version attribute of the winner's sx:sync element.
    2. Decrement n by the current version attribute of the loser's sx:sync item.
    3. Compare the when and by attributes of the loser's sx:history element with the corresponding attributes of the nth (1-based) sx:update sub-element of the winner. If n is 0, compare against the sx:history element of the winner.
    4. If the nth sx:update sub-element does not exist, assume NO CONFLICT; we are done processing conflict detection.
    5. If attribute values are equal, there is NO CONFLICT; we are done processing conflict detection.
    6. If they are not equal it is a CONFLICT; continue with step 2.
  2. If a conflict is detected, the conflict attribute on the sx:sync element MUST be set to "true"; else if a conflict is not detected, the value of the conflict attribute MUST be preserved.

4.4.2 CYCLE Detection

After comparison of all incoming items, all implementations for hierarchical data (e.g. OPML) MUST check if the results of comparison have caused an item to indirectly become a parent of itself. This is called cycle detection.

In order to detect cycles, endpoints MUST follow this algorithm:

  1. Traverse all items, one at a time, starting with the item with the lowest id value and ending with the highest id value (i.e. process items in ascending order)
  2. For each item, walk ancestry tree up to root node (e.g. channel or body element) to see if we encounter the same item again. If we do:
    1. Reparent item to root node.
    2. Set the conflict attribute on the sx:sync element to "true".

5 Optional Conflict Resolution Behavior

A user may want to "resolve" a conflict, where "resolve" means take an action resulting in a further update incrementing the version and removing the "conflict" attribute from sx:sync.

This spec allows for the saving of the actual contents of previous versions of the item attribute, so they can be presented to the user. This is done by adding and maintaining one or more optional sx:conflict sub-elements of an sx:conflicts element. One sx:conflict element is maintained for each entity who might have conflicted — that is, for each unique by specified in sx:update (or in sx:endpoint). Any number of sx:conflict elements may exist without a by value.

5.1 <sx:conflicts> element within <sx:sync>

The sx:conflicts element MUST contain one or more sx:conflict sub-elements.

5.2 <sx:conflict> element within <sx:conflicts>

Attributes Description
version A required, integer attribute. This is the version number of the conflicting modification.
when An optional, date-time attribute. This is the date-time when the conflicting modification took place. See sx:update for format guidance.

Note: Either or both of the when or by attributes MUST be present; it is invalid to have neither.

by An optional, string attribute. This text attribute identifies the endpoint that made the conflicting modification. It is used and compared programmatically. See sx:update for format guidance.

Note: Either or both of the when or by attributes MUST be present; it is invalid to have neither.

When a conflict happens, a sx:conflict sub-element is created by duplicating information from the loser's sx:history element into the newly-created sx:conflict element. Thus, the original SSE data of the losing modification is preserved. It is up to the application that is creating the sx:conflict element to provide any relevant conflict data as a child element(s).

When creating an sx:conflict sub-element, we always seek to maintain only a single such element for a given by, of the latest version. Meaning, if there is already such an element with the same by value but a lower version number, that sub-element is replaced with the new one.

If no by value exists for the either element, then comparison of the version and when attributes should occur. Meaning, if there is already an element with no by value, but a lower version number, that sub-element is replaced with the new one. In the event that version numbers are equal, if the existing element has lower when date, that sub-element is replaced with the new one.

Note  All sx:conflict elements are preserved as a flat, unordered list.

EXAMPLE

<item>
<description>This is a test item</description>
<sx:sync id="0a7903db47fb0ae8" version="4" conflict="true">
<sx:history when="Tue, 24 May 2005 09:43:33 GMT" by="REO1750">
<sx:update when="Mon, 23 May 2005 09:43:33 GMT" by="REO1750" />
</sx:history>
<sx:conflicts>
<sx:conflict when="Tue, 24 May 2005 08:00:11 GMT" by="GPM7383" version="4">
<!--conflict data here -->
</sx:conflict>
</sx:conflicts>
</sx:sync>
</item>

6 Licensing Information

Microsoft's copyrights in this specification are licensed under the Creative Commons Attribution-ShareAlike License (version 2.5). To view a copy of this license, please visit http://creativecommons.org/licenses/by-sa/2.5/. As to software implementations, Microsoft is not aware of any patent claims it owns or controls that would be necessarily infringed by a software implementation that conforms to the specification's extensions. If Microsoft later becomes aware of any such necessary patent claims, Microsoft also agrees to offer a royalty-free patent license on reasonable and non-discriminatory terms and conditions to any such patent claims for the purpose of publishing and consuming the extensions set out in the specification.