张可的博客

Atom 协议标准中文版

最近准备做一些 RSS 相关的工作,但是发现除了 RSS 协议之外官方还提供了个 Atom 协议,算是继承自 RSS 并且进行了一些扩展,相对要比 RSS 复杂很多,而网上也没找到中文资料,阅读文档的时候就想着看都看了,那就顺便(并不)翻译成中文吧。

1. 介绍

Atom 是一种基于 XML 的文档格式,主要用于描述 Feed 相关的信息列表。

Feeds 流由很多 entries(条目)组成,每个条目都包含一组可扩展的附加元数据,例如标题等等。

1.1 实例

一个简短的单项 Atom Feed 文档:

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="<http://www.w3.org/2005/Atom>">
   <title>Example Feed</title>
   <link href="<http://example.org/>"/>
   <updated>2003-12-13T18:30:02Z</updated>
   <author>
     <name>John Doe</name>
   </author>
   <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>

   <entry>
     <title>Atom-Powered Robots Run Amok</title>
     <link href="<http://example.org/2003/12/13/atom03>"/>
     <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
     <updated>2003-12-13T18:30:02Z</updated>
     <summary>Some text.</summary>
   </entry>
</feed>

或者一个更广泛的单项 Atom Feed 文档:

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="<http://www.w3.org/2005/Atom>">
   <title type="text">dive into mark</title>
   <subtitle type="html">
     A &lt;em&gt;lot&lt;/em&gt; of effort
     went into making this effortless
   </subtitle>
   <updated>2005-07-31T12:29:29Z</updated>
   <id>tag:example.org,2003:3</id>
   <link rel="alternate" type="text/html"
    hreflang="en" href="<http://example.org/>"/>
   <link rel="self" type="application/atom+xml"
    href="<http://example.org/feed.atom>"/>
   <rights>Copyright (c) 2003, Mark Pilgrim</rights>
   <generator uri="<http://www.example.com/>" version="1.0">
     Example Toolkit
   </generator>
   <entry>
     <title>Atom draft-07 snapshot</title>
     <link rel="alternate" type="text/html"
      href="<http://example.org/2005/04/02/atom>"/>
     <link rel="enclosure" type="audio/mpeg" length="1337"
      href="<http://example.org/audio/ph34r_my_podcast.mp3>"/>
     <id>tag:example.org,2003:3.2397</id>
     <updated>2005-07-31T12:29:29Z</updated>
     <published>2003-12-13T08:29:29-04:00</published>
     <author>
       <name>Mark Pilgrim</name>
       <uri><http://example.org/></uri>
       <email>f8dy@example.com</email>
     </author>
     <contributor>
       <name>Sam Ruby</name>
     </contributor>
     <contributor>
       <name>Joe Gregorio</name>
     </contributor>
     <content type="xhtml" xml:lang="en"
      xml:base="<http://diveintomark.org/>">
       <div xmlns="<http://www.w3.org/1999/xhtml>">
         <p><i>[Update: The Atom draft is finished.]</i></p>
       </div>
     </content>
   </entry>
</feed>

1.2 命名空间与版本

本规范中描述的 XML 数据格式的 XML 命名空间 URI 是:

http://www.w3.org/2005/Atom

方便起见,可以简写为"Atom 1.0".

1.3 符号约定

该规范描述了两个工件的一致性:Atom Feed Documents 与 Atom Entry Documents。

另外也对 Atom 解析程序提出了一些要求。

该规范使用 "atom:" 命名空间前缀表示上一节中的命名空间。但这并不是规范中的标准,可以任意选择,你甚至可以用 "rss:" ,只要你喜欢。

本文档中的关键词 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” 是被解释为 BCP_14, [RFC2119] 中描述的那样,以这些一致性目标为范围。

这里大概说下这几个关键词的意思:

2. Atom 文档

本规范描述了两种 Atom 文档:Atom Feed DocumentsAtom Entry Documents

Atom Feed Documents 用于描述 Atom feed(信息流),其中包含一些关于 feed 的元数据,以及与之相关联的 Entry(条目)。它的根结点是 atom:feed

Atom Entry Documents 仅用于描述一个 Atom Entry(条目),根结点为atom:entry

namespace atom = "<http://www.w3.org/2005/Atom>"
start = atomFeed | atomEntry

这两种 Atom 文档同样都遵守 XML Information Set 规范。使用 XML 1.0 序列化。媒体类型为 application/atom+xml。Atom 文档必须是格式良好的 XML。

Atom 文档中的每个元素都有可能(MAY)包含一个xml:base XML 属性,这个属性的定义在这里[W3C.REC-xmlbase-20010627],大概可以理解为 baseUrl,即定义了该属性的元素下面的 url 可以使用相对路径加上这个 baseUrl。

Atom 文档中的每个元素都有可能(MAY)包含一个xml:lang XML属性,它表示该元素以及其子元素中内容的自然语言类型。

综上所述,Atom 通用属性可能会包含 xml:basexml:lang,以及一些未定义的属性。因此我们做出如下定义。

atomCommonAttributes =
    attribute xml:base { atomUri }?,
    attribute xml:lang { atomLanguageTag }?,
    undefinedAttribute*

另外,Atom 是一种可扩展的格式,关于如何进行扩展后面会详细介绍。

3. Atom 通用结构(Common Atom Constructs)

许多 Atom 的元素共享一些共同的结构。 本节定义了这些结构和它们的要求,以方便相应的元素定义的引用。

当一个元素被认定为是一种特殊的结构时,它就继承了本节中该结构定义中的相应要求。

请注意,在 Date 结构体或任何 IRI 中都必须(MUST)不能有任何空白。 一些XML的实现在默认情况下会在值周围插入空白,这样的实现会发出无效的 Atom 文档。

3.1 文本结构(Text Constructs)

一个文本结构包含人类可读的文本,通常内容比较少。文本结构的内容是对语言敏感的。

定义如下:

atomPlainTextConstruct =
    atomCommonAttributes,
    attribute type { "text" | "html" }?,
    text

atomXHTMLTextConstruct =
    atomCommonAttributes,
    attribute type { "xhtml" },
    xhtmlDiv

atomTextConstruct = atomPlainTextConstruct | atomXHTMLTextConstruct

3.1.1 “type” 属性

文本结构可以有一个 type 属性。 其值必须(MUST)是 texthtmlxhtml 中的一个。

如果未提供 type 属性,则必须视为 text 类型。下面分别介绍这三种类型。

3.1.1.1 Text

举个例子,下面是一个包含文本内容的 title:

<title type="text">
     Less: &lt;
</title>

首先,text 类型的文本是决不能包含子元素的,该类型是为了直接呈现给用户的,需要保证其直接的可读性。

其次,Atom 的处理软件可能会删除其中的一些空白字符,通过某种文字排版技术进行排版。

3.1.1.2 HTML

再举个例子,下面是一个包含 HTML 内容的 title:

<title type="html">
     Less: &lt;em> &amp;lt; &lt;/em>
</title>

同样,html 类型的文本也是决不能包含子元素的,应该将其视作 HTML 格式来读取并显示。

其中包含的任何标记都应被转义后再显示。事实上,html 标记内容应该(SHOULD)是可以直接在 <DIV> 中显示的。

3.1.1.3 XHTML

下面是一个包含 XHTML 内容的 title:

<title type="xhtml" xmlns:xhtml="<http://www.w3.org/1999/xhtml>">
     <xhtml:div>
       Less: <xhtml:em> &lt; </xhtml:em>
     </xhtml:div>
</title>

xhtml 标记的内容必须是是一个单独的 XHTML div 元素,同时也应该适合作为 XHTML 进行处理。<xhtml:div> 元素本身并不应该被显示,应该按照处理程序转义之后再将其展示。

下面是另一个标准的例子:

...
 <summary type="xhtml">
    <div xmlns="<http://www.w3.org/1999/xhtml>">
       This is <b>XHTML</b> content.
    </div>
 </summary>
 ...
 <summary type="xhtml">
    <xhtml:div xmlns:xhtml="<http://www.w3.org/1999/xhtml>">
       This is <xhtml:b>XHTML</xhtml:b> content.
    </xhtml:div>
 </summary>
...

下面的例子假设 XHTML 命名空间已经在此之前被绑定到到文档中的 “xh” 前缀。

...
<summary type="xhtml">
  <xh:div>
     This is <xh:b>XHTML</xh:b> content.
  </xh:div>
</summary>
...

3.2 Person Constructs

Person Construct 是用于描述类似于人类、公司的元素。

atomPersonConstruct =
    atomCommonAttributes,
    (element atom:name { text }
     & element atom:uri { atomUri }?
     & element atom:email { atomEmailAddress }?
     & extensionElement*)

Person construct 主要包含了三个属性:name,uri,email,下面分别看下。

3.2.1 “atom:name” 元素

atom:name 元素内容表示一个人类可读的人名。其内容是语言敏感的(Language-Sensitive)。

Person Construct 必须包含一个 name 元素。

3.2.2 “atom:uri” 元素

atom:uri 元素包含一个关于这个人的 IRI,Person Construct 中可能(MAY)包含一个 atom:uri 元素,但是其个数必须不能(MUST NOT)超过一个。

3.2.3 “atom:email” 元素

atom:email 元素代表关于这个人的邮箱地址,Person Construct 中可能(MAY)包含一个 atom:email 元素,但是其个数必须不能(MUST NOT)超过一个。

3.3 Date Constructs

Person Construct 是用于描述日期时间的元素。其格式必须遵守 [RFC3339] 中对 date-time 的定义。此外,必须使用大写字母 “T” 来分隔日期和时间,如果没有数字时区偏移,则必须使用大写字母 “Z” 结尾。

atomDateConstruct =
    atomCommonAttributes,
    xsd:dateTime

下面是一些正确的例子:

<updated>2003-12-13T18:30:02Z</updated>
<updated>2003-12-13T18:30:02.25Z</updated>
<updated>2003-12-13T18:30:02+01:00</updated>
<updated>2003-12-13T18:30:02.25+01:00</updated>

日期最好(SHOULD)尽可能的准确。

4. Atom 元素定义

4.1 Container Elements(容器元素)

4.1.1 “atom:feed” 元素

atom:feed 元素是 Atom Feed Document 的顶层元素,被用作于元数据以及与之相关的元素的容器。其内容包含一些元数据以及零个或多个 atom:entry 元素。

atomFeed =
    element atom:feed {
       atomCommonAttributes,
       (atomAuthor*
        & atomCategory*
        & atomContributor*
        & atomGenerator?
        & atomIcon?
        & atomId
        & atomLink*
        & atomLogo?
        & atomRights?
        & atomSubtitle?
        & atomTitle
        & atomUpdated
        & extensionElement*),
       atomEntry*
    }

本规范未规定 “atom:entry” 的顺序,其顺序没有意义。

本规范对 atom:feed 元素的子元素做出如下定义:

如果一个 Atom Feed 文档中包含多个 atom:id 相同的 atom:entry ,那么他们的 atom:updated 中的时间戳应该是不同的。

处理程序可以自己选择显示方式,例如选择最新的 atom:entry

4.1.1.1 提供文本内容

根据经验,包含文本内容的 Feed 效果会更好,假如应用程序中包含一个文本搜索功能,需要依靠少量的文本进行搜索,那么文本内容就会比较有用。

因此,建议每个 atom:entry 都提供一个非空的 atom:title 元素,一个非空的 atom:content 元素,如果不提供 atom:content 可以提供一个非空的 atom:summary 元素。

4.1.2 “atom:entry” 元素

atom:entry 表示一个单独的条目,是其元数据以及相关数据的容器。

其可作为 atom:feed 元素的子元素出现,也可以作为一个独立的文档(即顶层元素)出现。

atomEntry =
    element atom:entry {
       atomCommonAttributes,
       (atomAuthor*
        & atomCategory*
        & atomContent?
        & atomContributor*
        & atomId
        & atomLink*
        & atomPublished?
        & atomRights?
        & atomSource?
        & atomSummary?
        & atomTitle
        & atomUpdated
        & extensionElement*)
    }

本规范同样没有规定 atom:entry 子元素的顺序,所以其顺序没有意义。

本规范对 atom:entry 元素的子元素做出如下定义:

4.1.3 “atom:content” 元素

atom:content 元素包含或者链接到条目的内容。atom:content 是语言敏感的。

atomInlineTextContent =
    element atom:content {
       atomCommonAttributes,
       attribute type { "text" | "html" }?,
       (text)*
    }

 atomInlineXHTMLContent =
    element atom:content {
       atomCommonAttributes,
       attribute type { "xhtml" },
       xhtmlDiv
    }

atomInlineOtherContent =
    element atom:content {
       atomCommonAttributes,
       attribute type { atomMediaType }?,
       (text|anyElement)*
    }

 atomOutOfLineContent =
    element atom:content {
       atomCommonAttributes,
       attribute type { atomMediaType }?,
       attribute src { atomUri },
       empty
    }

 atomContent = atomInlineTextContent
  | atomInlineXHTMLContent
  | atomInlineOtherContent
  | atomOutOfLineContent

如上所示,atomContent 包含四种类型的内容。

4.1.3.1 “type” 属性

atom:content 元素中,type 属性可能是 text/html/xhtml 中的一种,否则它必须是 MIME 媒体类型,但不可以是组合类型。

如果既没有提供 type 属性也没有提供 src 属性,那么应该按照 text 类型来进行处理。

4.1.3.2 “src” 属性

atom:content 元素可能包含一个 src 属性,其值必须是一个 IRI,如果提供了 src 属性,则 atom:content 内容必须为空。

如果提供了 src 属性,则应当提供 type 属性,且 type 属性必须是 MIME 媒体类型而不是 text/html/xhtml。此时,type 的值并非对应 IRI 的真正类型,当访问该 IRI 时还是要以 IRI 返回的媒体类型为准。

4.1.3.3 处理模式

Atom 文档以及 Atom 处理程序必须遵守以下规则。

  1. 如果 type 值为 text,atom:content 必须不能包含子元素,且内容将会被排版后直接显示,需要保证其可读性。
  2. 如果 type 值为 html,atom:content 必须不能包含子元素且需要是能被处理的 HTML,需要将其解析显示。
  3. 如果 type 值为 xhtml,atom:content 必须是单个 XHTML div 且需要是能被处理的 XHTML。
  4. 如果 type 值是个 XML 媒体类型或者以 +xml 或者 /xml 结尾,可能会包含子元素,且应当可以按照指定的格式进行处理,如果 src 属性未提供,一般可以认为 atom:content 元素包含单个子元素,且该元素是指定格式的 XML 文档的根元素。
  5. 如果 type 值以 text/ 开始,atom:content 必须不能包含子元素。
  6. 除了上面的 type 类型之外,atom:content 内容必须是个合法的 Base64 加密数据。

4.1.3.4 例子

XHTML inline:

...
 <content type="xhtml">
    <div xmlns="<http://www.w3.org/1999/xhtml>">
       This is <b>XHTML</b> content.
    </div>
 </content>
 ...
 <content type="xhtml">
    <xhtml:div xmlns:xhtml="<http://www.w3.org/1999/xhtml>">
       This is <xhtml:b>XHTML</xhtml:b> content.
    </xhtml:div>
 </content>
...

下面的例子假设 XHTML 命名空间已经在此之前被绑定到到文档中的 “xh” 前缀。

...
 <content type="xhtml">
    <xh:div>
       This is <xh:b>XHTML</xh:b> content.
    </xh:div>
 </content>
 ...

4.2 Metadata 元素

4.2.1 “atom:author” 元素

atom:author 是上面介绍过的 Person 结构(Person Construct),被用来表示 feed 或者 entry 的作者。

atomAuthor = element atom:author { atomPersonConstruct }

如果 atom:entry 元素中未包含 atom:author 元素,那么可以用 atom:source 中的 atom:author 元素,如果上述位置都不包含 atom:author 元素,那么可以用 atom:feed 中的 atom:author 元素。

4.2.2 “atom:category” 元素

atom:category 描述了关于这个 entry 或者 feed 的种类信息。本规范并为对其内容作出任何规定。

atomCategory =
    element atom:category {
       atomCommonAttributes,
       attribute term { text },
       attribute scheme { atomUri }?,
       attribute label { text }?,
       undefinedContent
    }

4.2.2.1 “term” 属性

term 属性表示 entry 或者 feed 所属种类的标识字符串。atom:category 元素必须包含一个 term 属性。

4.2.2.2 “scheme” 属性

scheme 属性是个表示分类方案的 IRI,atom:category 元素可能会包含它。

4.2.2.3 “label” 属性

label 属性提供了一个人类可读的标签用于显示在终端程序中,不应该对其中内容做转义,这不是标记,atom:category 元素可能会包含它。

4.2.3 “atom:contributor” 元素

atom:contributor 元素同样是个 Person 结构(Person Construct),表示该 entry 或者 feed 的贡献者。

4.2.4 “atom:generator” 元素

atom:generator 用于标识生成 feed 的代理,用于调试或者其他目的。

atomGenerator = element atom:generator {
    atomCommonAttributes,
    attribute uri { atomUri }?,
    attribute version { text }?,
    text
 }

如果元素提供了内容,那么必须是人类可读的文本,不应该对其内容做转义。

atom:generator 元素可能会包含一个 uri 属性,其值必须为 IRI。

atom:generator 元素可能会包含一个 version 属性,表示代理的版本。

4.2.5 “atom:icon” 元素

atom:icon 元素内容是一个 IRI,是 feed 的标识图像。

atomIcon = element atom:icon {
    atomCommonAttributes,
    (atomUri)
 }

这个图片的长宽比应当是一比一的,并且应当适合小尺寸展示。

4.2.6 “atom:id” 元素

atom:id 元素表示一个永久且普遍唯一的 entry 或 feed 标识符。

atomId = element atom:id {
    atomCommonAttributes,
    (atomUri)
 }

内容必须是 IRI,请注意这里的 IRI 并不包含相对引用。

当 Atom 文档被迁移、升级、聚合、再版、输出或者导入,atom:id 都必须不能改变。

atom:link 元素定义了从 entry/feed 到 Web 的引用,本规范对该元素的内容未做任何定义。

atomLink =
    element atom:link {
       atomCommonAttributes,
       attribute href { atomUri },
       attribute rel { atomNCName | atomUri }?,
       attribute type { atomMediaType }?,
       attribute hreflang { atomLanguageTag }?,
       attribute title { text }?,
       attribute length { text }?,
       undefinedContent
    }

4.2.7.1 “href” 属性

href 属性包含了连接的 IRI,atom:link 元素必须包含一个 href 属性,其值必须是 IRI 引用。

4.2.7.2 “rel” 属性

atom:link 元素可能包含一个 rel 属性,用于标识 link 关系类型。如果未提供 rel 属性,则 link 元素必须被解释为 alternate 类型。

rel 属性的值必须是个符合 RFC3987 规范的非空的字符串。

本规范为 rel 定义了五个初始值:

  1. alternate:表示 href 属性值的 IRI 标识了元素内容所描述内容的资源的另一个替代版本。
  2. related:表示 href 属性值的 IRI 标识了与元素内容相关的资源。
  3. self:表示 href 属性值的 IRI 标识了与元素内容相同的资源。
  4. enclosure:表示 href 属性值的 IRI 可能标识一个大尺寸资源,可能需要特殊处理,此时应当提供 length 属性。
  5. vie:表示 href 属性值的 IRI 标识了元素的信息来源。

4.2.7.3 “type” 属性

在 link 元素中,type 属性是个建议性的媒体类型:它是一个关于表示类型的提示,当引用 href 属性的值时,是预期会返回的类型。

需要注意的是,改类型属性并不覆盖实际的媒体类型和表示方法。

Link 元素可能包含一个 type 属性,其值必须遵守 MIME 媒体类型规范。

4.2.7.4 “hreflang” 属性

hreflang 属性描述了 href 属性所指向资源的语言,当与 rel=”alternate” 结合使用时,意味着该条目的翻译版本。

4.2.7.5 “title” 属性

title 属性是关于这个 link 的人类可读的描述,不需要对其内容进行转义,Link 元素可能包含它。

4.2.7.6 “length” 属性

length 属性标识了连接内容的建议长度(以八位字节为单位),但并不能保证其实际长度,Link 元素中可能包含它。

4.2.8 “atom:logo” 元素

atom:logo 元素内容是一个 IRI,是 feed 的标识图像。

atomLogo = element atom:logo {
    atomCommonAttributes,
    (atomUri)
 }

图像应的宽高比应该是2:1的。

4.2.9 “atom:published” 元素

atom:published 元素是个 Date Construct,表示 entry 生命周期中早期的事件的时间。

atomPublished = element atom:published { atomDateConstruct }

通常情况下,表示 entry 的创建时间或者首次可用时间。

4.2.10 “atom:rights” 元素

atom:rights **元素是个 Text Construct(文本结构),表示 entry/feed 的版权信息。

atomRights = element atom:rights { atomTextConstruct }

atom:rights **元素不应当**是机器语言描述的许可信息。

如果 atom:entry 中不包含 atom:rights 元素,那么 atom:feed 中的 atom:rights 元素则适用于此 entry。

4.2.11 “atom:source” 元素

如果一个 atom:entry 从另一个 feed 中复制过来,那么源 atom:feed 中的元数据可能会被隐藏,并且加入到 atom:source 元素的子元素中去。

如果源 atom:feed 中包含 atom:authoratom:contributoratom:rights 以及 atom:category 且这些子元素在源 atom:entry 中不存在,那么应该这几个数据应该被保留。

atomSource =
    element atom:source {
       atomCommonAttributes,
       (atomAuthor*
        & atomCategory*
        & atomContributor*
        & atomGenerator?
        & atomIcon?
        & atomId?
        & atomLink*
        & atomLogo?
        & atomRights?
        & atomSubtitle?
        & atomTitle?
        & atomUpdated?
        & extensionElement*)
    }

4.2.12 “atom:subtitle” 元素

atom:subtitle 元素是个人类可读的 Text Construct(文本构造器),被当做 feed 的描述或者子标题。

atomSubtitle = element atom:subtitle { atomTextConstruct }

4.2.13 “atom:summary” 元素

atom:summary 元素是个人类可读的 Text Construct(文本构造器),用于描述 entry 的摘要、摘录等。

atomSummary = element atom:summary { atomTextConstruct }

不建议让 atom:summary 元素与 atom:titleatom:content 重复。

4.2.14 “atom:title” 元素

atom:title 元素是个人类可读的 Text Construct(文本构造器),用于描述 entry/feed 的标题。

atomTitle = element atom:title { atomTextConstruct }

4.2.15 “atom:updated” 元素

atom:updated 是个 Date Construct(日期构造器) ,表示 entry/feed 的最近一次的修改时间。

atomUpdated = element atom:updated { atomDateConstruct }

发布者可能会随着时间推移修改这个元素的值。

结尾

Atom 协议总体就这么多,本人才疏学浅,如有出错请谅解,另外还有一些其他附加内容,奈何精力有限,且暂时对本人没有帮助,就没有对其翻译。

除了上面的文章外,我还在写一个 Kotlin 平台的 RSS 与 Atom 协议的序列化反序列化实现,过几天会完成,需要的可以关注我的更新。

附录

Atom 协议标准地址:*[https://datatracker.ietf.org/doc/html/rfc4287](https://datatracker.ietf.org/doc/html/rfc4287)