XEP-0060

来自Jabber/XMPP中文翻译计划
2010年9月30日 (四) 19:18Admin (讨论 | 贡献)的版本
跳转到: 导航, 搜索


本文的英文原文来自XEP-0060

XEP-0060: 发布-订阅

摘要: 本文定义了一个XMPP协议扩展来实现实现通用的 发布-订阅 功能。这个协议使 XMPP实体能在一个pubsub服务创建节点(主题)并发布信息到那些节点上;然后一个事件通知被广播到所有订阅了该节点的实体. PubSub因此坚持了经典的观察者设计模式,并可以作为广泛应用的服务基础,包括新闻提要,内容整合,富出席信息,地理位置,工作流系统,网络管理系统,以及任何其他需要事件通知的应用。

作者: Peter Millard, Peter Saint-Andre, Ralph Meijer

版权: © 1999 - 2010 XMPP标准化基金会(XSF). 参见法律通告.

状态: 草案

类型: 标准跟踪

版本: 1.13rc6

最后更新日期: 进展中,2009-10-01


注意: 这里定义的协议是XMPP标准化基金会的一个草案标准.对本协议的执行是被鼓励的,也适于布署到生产系统,但是在它成为最终标准之前可能还会有一些变动.


目录

绪论

概览

本文定义的XMPP 发布-订阅 扩展提供了一个框架用于广泛的应用, 包括新闻摘要, 内容整合, 扩展的出席信息, 地理位置, 头像管理, 共享的标签, 拍卖和贸易系统, 工作流系统, 网络管理系统, NNTP网关, 资料管理, 以及任何其他需要事件通知的应用.

这个技术使用了经典的 "发布-订阅" 或曰 "观察者" 设计模式: 一个人或应用发布信息, 同时一个事件通知 (包含或不包含有效载荷) 被广播到所有授权的订阅者. 通常, 发布者和订阅者之间的联系是由一个服务来调节的,这个服务接收发布请求,广播事件通知到订阅者, 并使有权限的实体能够管理被授权发布或订阅的人员或应用列表. 对于发布和订阅的焦点是一个节点 "node" ,它是发布者发送数据的目的地,也是订阅者接收通知的目的地. 节点也维护一个事件历史并提供其他服务以补充纯的 pubsub 模式.

本文定义一个通用的协议,所有 pubsub 应用都能使用. 兼容的实现不需要实现这里定义的所有特性 (参见 特性汇总.) 其他协议可以定义 发布-订阅 的子集 "subsets" 或范本 "profiles" 用于特定的场合, 但是这些范本超过了本文的范围.

它如何工作

尽管本协议很大,因为它定义了很多方面的用例, 基本的思路是简单的:

  1. 一个实体发布信息到一个 发布-订阅 服务上的一个节点.
  2. pubsub服务推送一个通知到所有被授权可以得知该发布信息的实体.

可能最流行的 发布-订阅 功能的应用是内容联合, 它常见于和博客,新闻网站,以及其他互联网可用的经常更新的信息相关联的 RSS 和 Atom (RFC 4287 1) 种子. 设想一个<hamlet@denmark.lit>的博客发布例子. 当 Hamlet 写下一篇新博文, 他的博客软件发布该文到一个位于<pubsub.shakespeare.lit>的pubsub节点:

例子 1. 发布者发布一篇新博文

<iq type='set'
    from='hamlet@denmark.lit/blogbot'
    to='pubsub.shakespeare.lit'
    id='pub1'>
  <pubsub xmlns='http://jabber.org/protocol/pubsub'>
    <publish node='princely_musings'>
      <item>
        <entry xmlns='http://www.w3.org/2005/Atom'>
          <title>Soliloquy</title>
          <summary>
To be, or not to be: that is the question:
Whether 'tis nobler in the mind to suffer
The slings and arrows of outrageous fortune,
Or to take arms against a sea of troubles,
And by opposing end them?
          </summary>
          <link rel='alternate' type='text/html'
                href='http://denmark.lit/2003/12/13/atom03'/>
          <id>tag:denmark.lit,2003:entry-32397</id>
          <published>2003-12-13T18:30:02Z</published>
          <updated>2003-12-13T18:30:02Z</updated>
        </entry>
      </item>
    </publish>
  </pubsub>
</iq>

所以那就是 发布-订阅 的发布 "pub" 部分.

现在 pubsub 服务通知所有订阅者新博文:

例子 2. 服务通知订阅者

<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo'>
  <event xmlns='http://jabber.org/protocol/pubsub#event'>
    <items node='princely_musings'>
      <item id='ae890ac52d0df67ed7cfdf51b644e901'>
        [ ... ENTRY ... ]
      </item>
    </items>
  </event>
</message>
 
<message from='pubsub.shakespeare.lit' to='bernardo@denmark.lit' id='bar'>
  <event xmlns='http://jabber.org/protocol/pubsub#event'>
    <items node='princely_musings'>
      <item id='ae890ac52d0df67ed7cfdf51b644e901'>
        [ ... ENTRY ... ]
      </item>
    </items>
  </event>
</message>
 
<message from='pubsub.shakespeare.lit' to='horatio@denmark.lit' id='baz'>
  <event xmlns='http://jabber.org/protocol/pubsub#event'>
    <items node='princely_musings'>
      <item id='ae890ac52d0df67ed7cfdf51b644e901'>
        [ ... ENTRY ... ]
      </item>
    </items>
  </event>
</message>
 
<message from='pubsub.shakespeare.lit' to='bard@shakespeare.lit' id='fez'>
  <event xmlns='http://jabber.org/protocol/pubsub#event'>
    <items node='princely_musings'>
      <item id='ae890ac52d0df67ed7cfdf51b644e901'>
        [ ... ENTRY ... ]
      </item>
    </items>
  </event>
</message>

这里是一个甚至更简单的例子: 一个临时的节点只发送通知而不带有效载荷:

例子 3. 一个临时通知

<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit'>
  <event xmlns='http://jabber.org/protocol/pubsub#event'>
    <items node='elsinore/doorbell'/>
  </event>
</message>

自然, 涉及的实体为了得到完整的 pubsub 功能可能需要完成其他用例 -- 例如, 发布者可能需要建立一个节点 (见 新建节点) 并且订阅者可能需要为通知报名(见 订阅节点). 这些用例在本文的 the remainder 有完整的描述. (关于哪些特性是必需的,哪些是推荐的活可选的信息, 参考 特性汇总.)

术语表=

以下术语用于本文中涉及的pubsub服务中的元素,对象,或动作.(注意: 本文的一些术语在正文中有更详细的解释.)

表 1: 出版-订阅 术语

术语 译文 术语解释
Authorize Access Model 授权访问模式 一个节点访问模式,一个实体只能在所有者批准了订阅申请之后才能订阅(订阅申请被接受但是只是临时的),并且只有订阅者可以接收项目.
Address 地址 (1) 一个 JID (定义在 XMPP Core [2])中, 或 (2) 一个JID和一个服务发现的联合 3 节点.
Collection Node 集合节点 一个节点类型,它包含很多节点 和/或 其他集合,但是不出版项目。集合使得多级节点结构成为可能
Entity 实体 一个以JID为地址的实体 (客户端,服务,应用程序等).
Event 事件 一个节点状态的一次变更
Instant Node 即时节点 一个节点,它的NodeID由pubsub服务自动生成
Item 条目 一个XML片段,它由一个节点发布, 从而生成一个事件
ItemID 条目ID 在一个一特定的节点中一个项目的唯一标识符
Leaf Node 叶子节点 一个节点类型,它仅包含已出版的项目. 它不是其他节点的一个容器
Node 节点 一个虚拟的位置,它的信息可以被发布,并且它的事件通知 和/或 有效载荷可以被接收(在其他pubsub系统中,可能被称为“topic”(主题))
NodeID 节点ID 在一个特定的pubsub服务中一个节点的唯一标识符,节点ID既由节点创建者提供,也由pubsub服务生成(如果节点创建者请求一个即时节点)。节点ID可以(MAY)有语义但是它的含义是可选的(OPTIONAL).
Notification 通知 一个发送给订阅者的消息通知他们一个事件
Outcast 被驱逐者 一个不被允许订阅或出版一个节点的实体
Owner 所有者 一个节点的管理者,可能不止一个; 经常(但不是必要的)是节点创建者
Payload 有效载荷 和一个事件相关的所有数据而不仅是事件通知本身.
Open Access Model 公开访问模式 一个节点访问模式,任何实体可以不用申请订阅和接收项目
Personal Eventing 私人事件 出版-订阅的一个简化的子集,用于即时消息和出席信息应用程序,每个用户的JID是一个虚拟的pubsub服务; 细节请看 Personal Eventing via Pubsub [4].
Presence Access Model 出席信息访问模式 一个访问模式,任何订阅了所有者出席信息(以类型"from" 或 "both"订阅)的实体,可以订阅一个节点并从节点接收项目;这个访问模式主要应用于即时消息系统。
Publisher 出版者 一个实体,被允许出版项目给一个节点
Pubsub Service 出版服务 一个遵循本文所定义的协议的 XMPP 服务器或组件
Roster Access Model 好友访问模式 一个节点访问模式,一个实体的出席信息被订阅了,只有特定的好友 组成员可以从节点订阅和接收项目;这个访问模式主要用于即时消息系统
Subscriber 订阅者 订阅了某个节点的一个实体
Whitelist Access Model 白名单访问模式 一个节点访问模式,一个实体只能被所有者为其添加订阅 ,并且只有订阅者可以接收项目

需求

pubsub服务的需求可能是由终端用户的需要驱动的,也包括其他可能使用这项服务的组件或服务器。首先,一个用Jabber实现的pubsub服务必须(MUST)提供基本的特性来实现一个纯的 出版-订阅 模式:

  • 一个实体必须(MUST)能够发布事件给一个服务,这样所有某个节点的订阅者能接收到事件通知.
  • 一个实体必须(MUST)被允许和一个节点从属。被允许的从属关系包括所有者(owner)、出版者(publisher)、无(none)、排斥者(outcast)。具体实现的时候,必须(MUST)支持所有者和无的关联,可以(MAY)支持排斥者和出版者的从属关系。
  • 一个实体必须(MUST)被允许查询一个pubsub服务(或一个指定的节点)以确定那些服务提供了本文定义的哪些可选的特性。这个查询必须(MUST)使用服务发现(disco#info)协议.
  • 一个实体必须(MUST)被允许查询一个节点以确定关于那个节点的非特性相关的信息(比如, 服务发现中的 类别和类型(category+type)). 这个查询必须使用服务发现 (disco#info) 协议.

一些基于Jabber的pubsub服务可能需要使用其他特性,但是这些特性是可选的(OPTIONAL)所以不是和本协议强制兼容的。无论如何,如果以下这些特性被实现了,它们必须(MUST)按照此处本协议的规定来保证兼容性。这些特性包括:

  • 一个服务可以(MAY)对一个节点缓存最近一次出版的项目(甚至即使"persistent-items"未被设置成true);如果它确实把缺省的 "cache-last-item" 设置成 true,它应该(SHOULD)按照"send_last_published_item"的配置发送最近出版的项目(或关于它的通知)给订阅的实体。
  • 一个节点所有者应该(SHOULD)能够指定谁可以订阅这个节点.
  • 一个节点所有者应该(SHOULD)能够指定谁可以发布项目到这个节点.
  • 一个节点可以(MAY)被配置成在事件通知内交付已出版的有效载荷。
  • 一个节点可以(MAY)被配置成持续发布项目给一些持久存储机制.
  • 一个节点可以(MAY)被配置成持续发布有限次数的项目.
  • 一个服务可以(MAY)支持集合.
  • 一个服务或节点可以(MAY)支持扩展的服务发现信息(meta-data).

预备

从属关系

为了管理许可,在这里协议定义了一个层次从属关系,类似多用户聊天系统中所采用的(Multi-User Chat 6).

对于 "owner" 和 "none" 的从属关系的支持是必需的(REQUIRED)。其他所有的从属关系的支持是建议的(RECOMMENDED)。特殊种类的pubsub服务可以(MAY)强制额外的需求。

表 2: 从属关系和他们的权限

从属关系 订阅 发布项目 清理项目 配置节点 删除节点 删除项目
所有者 Yes Yes Yes Yes Yes Yes
Publisher Yes Yes No No No Yes/No *
None Yes No No No No No
Outcast No No No No No No
  • 注意: 一旦一个项目已经出版给某个节点,那个服务可以(MAY)允许任何出版者删除任何项目而不是只允许原始的出版者删除它(这是一个可发现的服务,通过"pubsub#delete-any"特性)。

实体如何变更它和节点的从属关系是很明确的。一般来讲,一个从属关系状态的改变需要所有者的动作。从属关系改变和他们的触发动作定义在下表中。

表 3: 从属关系状态图

Outcast -- 所有者移除禁令 所有者添加实体到出版者列表 所有者添加实体到所有者列表
None 所有者禁止实体 -- 所有者添加实体到出版者列表 所有者添加实体到所有者列表
Publisher 所有者禁止实体 所有者从出版者列表中移除实体 -- 所有者添加实体到所有者列表
Owner n/a 所有者辞职 n/a --

订阅状态

订阅某个节点可以有很多状态

表 4: 订阅状态

订阅状态 描述
节点不能(MUST NOT)发送事件通知或有效载荷给实体.
未决的 一个实体已经申请订阅一个节点,但是这个申请还没被节点所有者批准。节点在处于这个状态时不能(MUST NOT)发送事件通知或有效载荷给实体。
未配置的 一个节点已经订阅但是它的订阅选项还没有配置。节点在这个状态时可以(MAY)发送事件通知或有效载荷给实体。 服务可以(MAY)让未配置的订阅过期作废。
已订阅的 一个实体已经订阅了一个节点。节点在这个状态下必须(MUST)发送所有事件通知(和有效载荷,如果配置了的话)给实体。

事件类型

出版-订阅协议需要两个主要的尺度来使我们能够衡量一个事件:持久性和临时性,纯的通知和包含有效载荷的通知。协议的实现应该(SHOULD)让所有者能够从两个尺度都可以配置一个节点。

无论一个节点是否配置成持久性或者临时性的事件,一个服务可以(MAY)缓存最后一个发布到节点的项目,在这种情况下,它应该(SHOULD)根据"send_last_published_item"选项(参见本文的 项目缓存 章节)的配置情况发送那个项目给订阅者。

一个pubsub服务必须(MUST)确认发布请求在这两个方面都满足节点的配置。(参见本文的 发布一个项目到一个节点 章节了解相关的出错条件)。

是否一个项目必须由一个出版者提供,以及是否一个项目ID由出版者提供还是有pubsub服务生成,取决于被发布的事件的类型。我们在下表中概述相关的规则:

表 5: 事件类型,项目,项目ID

持久的 发布者必须(MUST)包含一个 <item/> 元素,它可以(MAY)是空的或者包含有效载荷;如果项目 ID 不是由发布者提供,它必须(MUST)由pubsub服务生成 发布者必须(MUST)包含一个 <item/> 元素,其中包含有效载荷;如果项目 ID 没有被发布者提供,它必须(MUST)由pubsub服务生成
临时的 发布者不能(MUST NOT)包含一个 <item/> 元素(所以项目 ID 不需要提供也不需要生成) 但是通知将包含一个空的 <items/> 元素 发布者必须(MUST)包含一个 <item/> 元素,其中包含有效载荷,但是项目 ID 是可选的(OPTIONAL)

节点类型

有两个节点类型:

表 6: 节点类型

节点类型 描述
叶节点 一个仅包含发布的项目的节点。它不包含任何其他节点。这是最常见的节点类型。
集合节点 一个包含节点和/或其他集合但是不包含出版项目的节点。集合可以实现多层次的节点结构。

节点访问模式

为了使节点建立对客户更简单,我们定义了以下节点访问模式(为了公开性):

表 7: 节点访问模式

访问模式 描述
开放的 任何实体可以订阅这个节点(比如, 订阅不需要批准) ,以及任何实体可以从这个节点接收项目(比如,不需要被订阅);这应该(SHOULD)是一般pubsub幅服务的缺省访问模式。
持久的 任何拥有"from"或"both"类型的订阅的实体可以向节点订阅和接收项目;这个访问模式主要应用于即时消息系统 (参见 RFC 3921).
名册 任何处于指定名册组中的实体可以向节点订阅和接收项目;这种访问模式主要用于即时消息系统 (参见see RFC 3921).
授权的 节点所有者必须批准所有订阅请求,并且只有订阅者可以从节点接收项目.
白名单 一个实体仅仅在被节点所有者加入白名单的时候才可以被订阅(主动提出的订阅请求会被拒绝),并且只有订阅者可以从节点接收项目。换句话说,缺省的从属关系是排斥的。节点所有者必须(MUST)自动进入白名单。为了添加实体进入白名单,节点所有者应该(SHOULD)使用本文的 管理从属关系实体章节中所定义的方式。

尽管专门的出版-订阅 系统实施可以(MAY)只支持访问模式的一个子集,但一般来说 出版-订阅系统实施应该(SHOULD)支持所有已定义的访问模式。在一个专门部署的系统中,系统服务提供哪些访问模式是一个问题(比如,一些受限的系统部署可能希望锁定许可从而只提供“被授权的”和"白名单"的访问模式,或甚至只提供"白名单"的访问模式)。

为了使一个节点创建者或所有者指定访问模式,使用了'pubsub#access_model'配置域(参见本文的Create a Node With Default Configuration and Configure a Node(以缺省配置创建一个节点和配置一个节点)章节).

寻址

如果一个 pubsub 节点是可设定地址的,它必须(MUST)被设定为一个JID或一个JID和一个节点的组合。\[7\]

JID

如果一个 pubsub 节点的地址被设定成一个JID,节点ID必须(MUST)是资源ID,并且节点ID不能(MUST NOT)是JID中的"user"部分(如"domain.tld/NodeID" 和 "user@domain.tld/NodeID" 是被允许的; "NodeID@domain.tld" 是不允许的)。JID 寻址应该(SHOULD)在使用不支持节点属性的协议和一个 pubsub 节点互动的时候使用.例如,当一个服务允许实体向节点订阅出席信息,它会把节点地址设成JID。如果一个 pubsub 节点可以被设置成 JID ,pubsub 服务必须(MUST)确保节点ID符合 RFC 3920中规定的Resourceprep profile of Stringprep。

考虑以下例子,pubsub服务定位于主机名 pubsub.shakespeare.lit.

案例 4. 节点地址设定为 domain.tld/NodeID

<iq to='pubsub.shakespeare.lit/news announcements'>
    ...
</iq>

现在再考虑以下例子, pubsub 服务定位于 pubsub@shakespeare.lit.

案例 5. 节点地址设定为 user@domain.tld/NodeID

<iq to='pubsub@shakespeare.lit/news announcements'>
    ...
</iq>

JID+NodeID

如果一个pubsub服务地址可以被设成一个JID加一个节点,这个节点ID必须(MUST)是发现服务中的'node'属性值,同时也是pubsub服务的'node'属性值;用于发现服务时,一个pubsub节点等同于一个发现服务的节点。如果一个pubsub节点可以被设置成 JID 加 node,这个pubsub服务应该(SHOULD)确保节点ID符合 RFC 3920中规定的Resourceprep profile of Stringprep。

考虑以下例子,(虚拟的)pubsub服务定位于 hamlet@denmark.lit.

案例 6. 节点地址设为 JID+NodeID

<iq to='hamlet@denmark.lit'>
    <query node='princely_musings'/>
</iq>

实体用例

本章规定了使用案例,用于任何希望和出版-订阅服务互动的实体使用的协议,主要集中于发现服务的使用案例。

发现特性

一个服务必须(MUST)回应符合名字空间'http://jabber.org/protocol/disco#info'的发现服务信息请求。由pubsub服务返回的"disco#info"结果必须(MUST)表明服务的标识符以及支持哪些pubsub特性。

案例 7. 实体查询 Pubsub 服务支持的特性

<iq type='get'
    from='francisco@denmark.lit/barracks'
    to='pubsub.shakespeare.lit'
    id='feature1'>
   <query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>

案例 8. Pubsub 服务返回支持的特性组

<iq type='result'
    from='pubsub.shakespeare.lit'
    to='francisco@denmark.lit/barracks'
    id='feature1'>
   <query xmlns='http://jabber.org/protocol/disco#info'>
       <identity category='pubsub' type='service'/>
       <feature var='http://jabber.org/protocol/pubsub'/>
   </query>
</iq>

可能存在的 pubsub 特性在本文中到处都是,并且它们都已经在本文的 XMPP资源注册事项 章节描述了。想了解哪个特性是必需的,建议的,可选的,参见本文的 特性总结 章节。

5.2 发现节点

如果一个服务实现了一个多层次节点(也就是 集合节点),它必须(MUST)也要让实体能够通过 服务发现协议发现这些多层次节点,在结果集很大的时候遵照 XEP-0030 的建议(这时候应该(SHOULD)使用Jabber search或一些其他协议).以下例子展示在一个多层次 pubsub 服务中如何使用 服务发现 来发现可用的节点.


注意: 节点层次和集合节点是可选的(OPTIONAL). 详细情况参照本文的 节点ID术语 和 集合节点章节.


在第一个例子中,一个实体向一个根节点(比如服务本身)发送一个服务发现条目("disco#items")请求,它是一个集合节点:


__案例 9. 实体请求所有一级节点__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='nodes1'>


<query xmlns='http://jabber.org/protocol/disco#items'/>


</iq>

{code}


__案例 10. 服务返回所有一级节点__ {anchor:xml}


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='nodes1'>


<query xmlns='http://jabber.org/protocol/disco#items'>


<item jid='pubsub.shakespeare.lit' node='blogs' name='Weblog updates'/>


<item jid='pubsub.shakespeare.lit' node='news' name='News and announcements'/>


</query>


</iq>

{code}


第二个例子中,一个实体发送一个 disco#items 请求给其中一个一级节点,它也是一个集合节点:


__案例 11. 实体请求二级节点__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='nodes2'>


<query xmlns='http://jabber.org/protocol/disco#items' node='blogs'/>


</iq>

{code}


__案例 12. 服务返回二级节点__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='nodes2'>


<query xmlns='http://jabber.org/protocol/disco#items' node='blogs'>


<item jid='pubsub.shakespeare.lit' node='princely_musings'/>


<item jid='pubsub.shakespeare.lit' node='kingly_ravings'/>


<item jid='pubsub.shakespeare.lit' node='starcrossed_stories'/>


<item jid='pubsub.shakespeare.lit' node='moorish_meanderings'/>


</query>


</iq>

{code}


如果一个叶子节点不仅是一个集合节点,它本身也有条目发行,这个服务可以(MAY)为每一个已出版的条目返回一个 <item/> 元素(参见本文的 从一个节点发现条目 章节),无论如何这些条目一定不能(MUST NOT)包含一个 'node' 属性(因为它们是已发行的条目,不是节点).


__5.3 发现节点信息__ {anchor:发现节点信息}


一个 pubsub 服务必须(MUST)允许实体去查询每个单独的节点来获得该节点的相关信息。必须(MUST)使用服务发现协议来查询这些信息。"disco#info" 结果必须(MUST)包含一个ID,其类别是“pubsub”,类型是“leaf”或“collection”。


注意: 如果一个节点的 id 类型为“leaf”,它一定不能(MUST NOT)包含其它的节点或集合(只有条目);如果一个节点的ID类型是“collection”,它一定不能(MUST NOT)包含条目(只有其它节点或集合)。


__案例 13. 实体查询集合节点的信息__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='info2'>


<query xmlns='http://jabber.org/protocol/disco#info' node='blogs'/>


</iq>

{code}


__案例 14. 服务应答 pubsub/collection ID__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='meta1'>


<query xmlns='http://jabber.org/protocol/disco#info' node='blogs'>


...


<identity category='pubsub' type='collection'/>


...


</query>


</iq>

{code}


__案例 15. 实体查询叶子节点信息__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='info1'>


<query xmlns='http://jabber.org/protocol/disco#info' node='princely_musings'/>


</iq>

{code}


__案例 16. 服务应答 pubsub/collection ID__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='info1'>


<query xmlns='http://jabber.org/protocol/disco#info'>


...


<identity category='pubsub' type='leaf'/>


...


</query>


</iq>

{code}


__5.4 发现节点元数据__ {anchor:发现节点元数据}


"disco#info" 结果可以(MAY)包含节点的详细元数据,封装在数据窗体[第九章]中,其格式参见Service Discovery Extensions(服务发现扩展) [第十章]。数据窗体上下文由 "http://jabber.org/protocol/pubsub#meta-data" 中的 FORM_TYPE 定义,并符合Field Standardization for Data Forms(数据窗体的字段标准化)[第十一章]。如果元数据被提供了,它应该(SHOULD)所有已配置的选项值,像"automatic" 信息一样,比如节点创建日期,出版者列表以及类似的信息。


__案例 17. 实体查询一个节点的信息__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='meta1'>


<query xmlns='http://jabber.org/protocol/disco#info' node='princely_musings'/>


</iq>

{code}


__案例 18. 服务应答信息和元数据__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='meta1'>


<query xmlns='http://jabber.org/protocol/disco#info' node='princely_musings'/>


<identity category='pubsub' type='leaf'/>


<feature var='http://jabber.org/protocol/pubsub'/>


<x xmlns='jabber:x:data' type='result'>


<field var='FORM_TYPE' type='hidden'>


<value>>>http://jabber.org/protocol/pubsub#meta-data</value>


</field>


<field var='pubsub#type' label='Payload type'>


<value>>>http://www.w3.org/2005/Atom</value>


</field>


<field var='pubsub#creator' label='Node creator'>


<value>hamlet@denmark.lit</value>


</field>


<field var='pubsub#creation_date' label='Creation date'>


<value>2003-07-29T22:56Z</value>


</field>


<field var='pubsub#title' label='A short name for the node'>


<value>Princely Musings (Atom)</value>


</field>


<field var='pubsub#description' label='A description of the node'>


<value>Updates for Hamlet's Princely Musings weblog.</value>


</field>


<field var='pubsub#language' label='Default language'>


<value>en</value>


</field>


<field var='pubsub#contact' label='People to contact with questions'>


<value>bard@shakespeare.lit</value>


</field>


<field var='pubsub#owner' label='Node owners'>


<value>hamlet@denmark.lit</value>


</field>


<field var='pubsub#publisher' label='Publishers to this node'>


<value>hamlet@denmark.lit</value>


</field>


<field var='pubsub#num_subscribers' label='Number of subscribers to this node'>


<value>1066</value>


</field>


</x>


</query>


</iq>

{code}


注意: 节点元数据可以用多种方法设置。一些是基于节点配置(如所有者的JID),也有的是动态的(如订阅者的号码)。任何在节点元数据中提供的静态信息应该(SHOULD)在节点配置窗体中以字段形式提供。


更多的元数据直接由节点映射表中特定的元数据属性提供。参见Dublin Core Metadata Initiative (DCMI) [第十二章]:


__表 8: Dublin Core Meta-Data Mapping(Dulbin 核心元数据映射表)__


{table}

Pubsub Field |Dublin Core Meta-Data Attribute

pubsub#creation_date |Date [第十三章]

pubsub#creator |Creator

pubsub#description |Description

pubsub#language |Language

pubsub#publisher |Publisher

pubsub#title |Title

pubsub#type |Type [第十四章]

{table}


__5.5 从一个节点查询条目__ {anchor:从一个节点查询条目}


为了查询服务中特定节点的已出版条目,一个实体可以(MAY)发送"disco#items"请求给节点本身,服务可以(MAY)通过< item/>返回每个条目。每个条目的'name'属性必须(MUST)包括它的ItemID,并且条目不能(MUST NOT)有'node'属性。这个 ItemID 可以(MAY)用于接收条目(参见本协议文档中Retrieve Items from a Node(从一个节点接收条目) 章节 ).


__案例 19. 实体请求一个节点的所有条目__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='items1'>


<query xmlns='http://jabber.org/protocol/disco#items' node='princely_musings'/>


</iq>


<iq type='result' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='items1'>


<query xmlns='http://jabber.org/protocol/disco#items' node='princely_musings'>


<item jid='pubsub.shakespeare.lit' name='368866411b877c30064a5f62b917cffe'/>


<item jid='pubsub.shakespeare.lit' name='3300659945416e274474e469a1f0154c'/>


<item jid='pubsub.shakespeare.lit' name='4e30f35051b7b8b42abe083742187228'/>


<item jid='pubsub.shakespeare.lit' name='ae890ac52d0df67ed7cfdf51b644e901'/>


</query>


</iq>

{code}


__5.6 找回订阅__ {anchor:找回订阅}


一个服务应该(SHOULD)允许实体查询服务以找回它对服务中所有节点的订阅。为了做出这些查询,请求的实体必须(MUST)发送一个 IQ-get 消息,这个消息的 <pubsub/> 子元素包含一个没有属性的空<subscriptions/>元素。


__案例 20. 实体请求所有当前的订阅__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='subscriptions1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscriptions/>


</pubsub>


</iq>

{code}


如果服务返回一个订阅列表,它必须(MUST)返回所有和请求消息中'from'属性的 纯JID (<node@domain.tld>) 匹配的 JIDs的信息.


对于每个订阅, 返回一个 <subscription/> 元素以指明 NodeID, 以及这个节点ID相关联的 JID(可以包含资源,视实体如何订阅而定),目前的订阅状态。如果服务支持订阅ID(subscription identifier),'subid' 属性也必须(MUST)出现.


__案例 21. 服务返回所有当前订阅__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit'
   id='subscriptions1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscriptions>


<subscription node='node1' jid='francisco@denmark.lit' subscription='subscribed'/>


<subscription node='node2' jid='francisco@denmark.lit' subscription='subscribed'/>


<subscription node='node5' jid='francisco@denmark.lit' subscription='unconfigured'/>


<subscription node='node6' jid='francisco@denmark.lit' subscription='pending'/>


</subscriptions>


</pubsub>


</iq>

{code}


如果请求实体没有订阅,pubsub 服务必须(MUST)返回一个空的 <subscriptions/> 元素.


__案例 22. 没有订阅__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='subscriptions1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscriptions/>


</pubsub>


</iq>

{code}


如果服务不支持订阅找回,服务必须(MUST)应答一个<feature-not-implemented/> 错误, 指出 pubsub-specific 的错误条件 <unsupported/> 以及特性 "retrieve-subscriptions".


__案例 23. 不支持订阅找回__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='subscriptions1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscriptions/>


</pubsub>


<error type='cancel'>


<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


<unsupported xmlns='http://jabber.org/protocol/pubsub#errors' feature='retrieve-subscriptions'/>


</error>


</iq>

{code}


__5.7 找回加入__ {anchor:找回加入}


一个服务应该(SHOULD)允许一个实体查询这个服务以找回它在所有节点的加入信息。为了做出这些请求,实体要在请求消息中包含一个没有属性的空 <affiliations/> 元素。


__案例 24. 实体请求所有当前加入__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='affil1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<affiliations/>


</pubsub>


</iq>

{code}


如果服务返回一个加入的列表,它必须(MUST)返回所有和请求的'form'属性的 纯JID (<node@domain.tld>)相匹配的JID的加入信息。


对于每个加入信息, 返回一个 <affiliation/> 元素,包含 NodeID 和加入状态 (所有这owner, 发布者publisher, or 流浪者outcast).


__案例 25. 服务应答所有当前加入__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit'
   id='affil1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<affiliations>


<affiliation node='node1' affiliation='owner'/>


<affiliation node='node2' affiliation='publisher'/>


<affiliation node='node5' affiliation='outcast'/>


<affiliation node='node6' affiliation='owner'/>


</affiliations>


</pubsub>


</iq>

{code}


如果请求实体没有加入, pubsub 服务必须(MUST)返回一个空的 <affiliations/> 元素.


__案例 26. 没有加入__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='affil1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<affiliations/>


</pubsub>


</iq>

{code}


如果服务不支持加入找回, 服务必须(MUST)应答一个 <feature-not-implemented/> 错误, 指明一个 <unsupported/>的 pubsub-specific 错误条件和 "retrieve-affiliations" 的特性.


__案例 27. 不支持加入找回__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='affil1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<affiliations/>


</pubsub>


<error type='cancel'>


<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


<unsupported xmlns='http://jabber.org/protocol/pubsub#errors' feature='retrieve-affiliations'/>


</error>


</iq>

{code}


__6. 订阅者用例__ {anchor:订阅者用例}


本节定义了潜在和实际的订阅者使用协议的用例。(注意:本文的实施备注一节描述了一个pubsub服务器必须(MUST)遵守的许多重要的因素和商业规则.另外,所有例子都假定独立的pubsub组件存在并包含任何含有服务器或网络标记的相关'from'地址).


__6.1 向一个节点订阅__ {anchor:向一个节点订阅}


当一个Jabber实体希望从一个节点订阅,它向pubsub服务发送订阅请求。订阅申请是一个 IQ-set 消息,其<pubsub/> 元素包含并且仅包含一个<subscribe/>元素.这个<subscribe/>元素必须(MUST)拥有一个'node' 属性指明实体希望订阅的节点.这个<subscribe/>元素必须(MUST)拥有一个'jid' 属性指明用于订阅的JID确切的 XMPP 地址--通常是一个纯JID(<node@domain.tld>) 或一个全JID(<node@domain.tld/resource>),当然<domain.tld> 或 <domain.tld/resource>格式的JID也可以订阅.


如果指定的JID 是一个纯JID或一个全JID,服务必须(MUST)从接收的IQ请求中的’from’属性中分离出最小化的纯JID部分,以确保发出请求的实体和被加入到订阅者列表的JID是同一个ID。无论如何,一些实现可以(MAY)允许服务管理员配置一个实体列表不进行此项检查;那些实体可能被作为 "trusted proxies"(被信任的代理),可以为其他实体进行订阅.同样的,一些实现可以(MAY)允许实体黑名单,禁止其执行特定的动作(比如订阅或者建立节点).


一个服务可以(MAY)允许实体多次订阅同一个节点.这是一个实体能够用不同的订阅选项进行订阅.如果允许用同一个JID进行多次订阅,服务必须(MUST)使用'subid'属性来区分同一实体的不同订阅(所以SubID必须(MUST)对于每一个node+JID的组合是唯一的,并且在发送给订阅者实体的任何时候SubID必须(MUST)出现在实体元素中)。不建议(NOT RECOMMENDED)客户端生成SubID,因为可能引发冲突;所以一个服务应该(SHOULD)为订阅者生成一个SubID,并且如果订阅者提供了 SubID,服务可以重写它.如果服不允许同一个实体多次订阅但是接收到了额外的订阅请求,服务必须(MUST)返回当前的订阅状态(如果这个订阅以前就被批准了).


这里是一个订阅请求的例子.


__案例 28. 实体向一个节点订阅__


{code:xml}

<iq type='set'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


</iq>

{code}


如果订阅请求被成功处理,服务器必须(MUST)通知请求实体它已订阅(可以(MAY)包含一个服务生成的SubID).


__案例 29. 服务返回成功__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscription node='princely_musings' jid='francisco@denmark.lit' subid='ba49252aaa4f5d320c24d3766f0bdcade78c78d3' subscription='subscribed'/>


</pubsub>


</iq>

{code}


服务也可以(MAY)发送最后一次发行的条目给新的订阅者.包含这个条目的消息应该(SHOULD)被标记为符合'jabber:x:delay'名字空间的扩展信息(参见 Delayed Delivery [第十五章]),以表明它是延时发送的.(注意在这个例子中消息通知发送给纯JID,因为那是已订阅的JID)


__案例 30. 服务发送最后一次发行的条目__


{code:xml}

<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit'>


<event xmlns='http://jabber.org/protocol/pubsub#event'>


<items node='princely_musings'>


<item id='ae890ac52d0df67ed7cfdf51b644e901'>


<entry xmlns='http://www.w3.org/2005/Atom'>


<title>Soliloquy</title>


<summary> To be, or not to be: that is the question: Whether 'tis nobler in the mind to suffer The slings and arrows of outrageous fortune, Or to take arms against a sea of troubles, And by opposing end them? </summary>


<link rel='alternate' type='text/html' href='http://denmark.lit/2003/12/13/atom03'/>


<id>tag:denmark.lit,2003:entry-32397</id>


<published>2003-12-13T18:30:02Z</published>


<updated>2003-12-13T18:30:02Z</updated>


</entry>


</item>


</items>


</event>


<x xmlns='jabber:x:delay' stamp='20031213T23:58:37'/>


</message>

{code}


有很多原因可能导致订阅请求失败:


  1. JID 的纯JID部分不符.
  1. 节点有一个"presence"访问模式并且请求实体没有订阅所有者的出席信息。
  1. 节点有一个"roster"的访问模式并且请求实体不在授权名单组中。
  1. 节点有一个"whitelist"的访问模式并且请求实体不在白名单中。
  1. 订阅节点的时候服务需要付费。
  1. 请求实体是匿名的并且服务不允许匿名实体订阅。
  1. 请求实体有一个未决的订阅。
  1. 请求实体被封锁订阅(例如,因为被加入黑名单)。
  1. 节点不支持订阅。
  1. 节点不存在。


这些错误案例全部描述如下.


如果JID的纯JID部分不符合上述的描述并且请求实体没有一些由实现定义的管理或者代理权限,服务必须(MUST)返回一个<bad-request/>错误,它也应(SHOULD)包含一个pubsub- specific的<invalid-jid/>错误条件。


__案例 31. JID不匹配__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscribe node='princely_musings' jid='bernardo@denmark.lit'/>


</pubsub>


<error type='modify'>


<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


<invalid-jid xmlns='http://jabber.org/protocol/pubsub#errors'/>


</error>


</iq>

{code}


对于拥有"presence"访问模式的节点,如果请求实体没有订阅所有者的出席信息,pubsub服务必须(MUST)返回一个 <not-authorized/> 错误,它也应该(SHOULD)包含一个 pubsub-specific 的<presence-subscription-required/>错误条件。


__案例 32. 实体没有被授权建立一个订阅(需要出席信息订阅)__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='auth'>


<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


<presence-subscription-required xmlns='http://jabber.org/protocol/pubsub#errors'/>


</error>


</iq>

{code}


对于拥有"roster"访问模式的节点,如果请求实体不在授权的名单组中,pubsub服务必须(MUST)返回一个 <not-authorized/> 错误,它也应该(SHOULD)包含一个 pubsub-specific 的<not-in-roster-group/>错误条件。


__案例 33. 实体没有被授权建立一个订阅(不在名册组中)__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='auth'>


<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


<not-in-roster-group xmlns='http://jabber.org/protocol/pubsub#errors'/>


</error>


</iq>

{code}


对于拥有"白名单"访问模式的节点,如果请求实体不在白名单中,pubsub服务必须(MUST)返回一个 <not-authorized/> 错误,它也应该(SHOULD)包含一个 pubsub-specific 的<closed-node/>错误条件。


__案例 34. 节点有白名单访问模式__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='cancel'>


<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


<closed-node xmlns='http://jabber.org/protocol/pubsub#errors'/>


</error>


</iq>

{code}


商业部署可能希望把订阅连接到一个付费客户数据库。如果为了订阅节点需要付费(例如,如果订阅者不在客户数据库中或客户还未付帐),服务应该(SHOULD)返回一个 <payment-required/> 错误给订阅者。


__案例 35. 订阅需要付费__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='auth'>


<payment-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


</error>


</iq>

{code}


一些 XMPP 服务器可能允许使用SASL ANONYMOUS验证;无论如何,因为这会导致实体不稳定(分配的JID可能不是同一个负责人in a persistent manner),一个服务可以(MAY)防止匿名实体订阅一个节点并且应该(SHOULD)使用服务发现来决定是否有一个 "account/anonymous"实体.如果一个请求实体是匿名的但是服务器不允许匿名实体订阅,服务应该返回一个< forbidden/>错误给订阅者.


__案例 36. 请求实体是匿名用户__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='anonymous@denmark.lit/foo'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscribe node='princely_musings' jid='anonymous@denmark.lit'/>


</pubsub>


<error type='cancel'>


<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


</error>


</iq>

{code}


如果请求实体有一个未决的订阅, 服务必须(MUST)返回一个<not-authorized/>错误给订阅,表明一个发生了pubsub-specific <pending-subscription/>错误条件.


__案例 37. 请求实体有一个未决的订阅__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='auth'>


<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


<pending-subscription xmlns='http://jabber.org/protocol/pubsub#errors'/>


</error>


</iq>

{code}


如果请求实体被一个订阅屏蔽了(例如, 因为它在禁止加入的名单中), 服务器必须(MUST)返回一个<forbidden/>错误给订阅者.


__案例 38. 请求实体被屏蔽__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='auth'>


<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


</error>


</iq>

{code}


如果节点不允许实体订阅, 服务应该(SHOULD)返回一个<feature-not-implemented/>错误给订阅者,提出一个pubsub- specific <unsupported/>错误条件和一个"subscribe"特性.


__案例 39. 订阅不支持__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='cancel'>


<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


<unsupported xmlns='http://jabber.org/protocol/pubsub#errors' feature='subscribe'/>


</error>


</iq>

{code}


如果节点不存在, 服务应该(SHOULD)返回一个<item-not-found/>错误给订阅者.


__案例 40. 节点不存在__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='cancel'>


<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


</error>


</iq>

{code}


对于拥有"authorize"访问模式的节点, 订阅请求必须(MUST)由节点所有者批准; 所以pubsub服务发送一个消息给节点所有者请求授权(参见本文的 Manage Subscription Requests 章节). 因为订阅请求可能被批准也可能不被批准, 服务必须(MUST)返回一个未决通知给订阅者.


__案例 41. 服务应答未决__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscription node='princely_musings' jid='francisco@denmark.lit' subscription='pending'/>


</pubsub>


</iq>

{code}


如果实体在接收通知之前必须配置它的订阅选项(见本文 Configure Subscription Options 章节),服务必须(MUST)通知实体这件事. 它应该(SHOULD)返回一个IQ-result给请求实体一个记号表示需要订阅配置。


__案例 42. 服务应答成功并指出需要配置订阅__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscription node='princely_musings' jid='francisco@denmark.lit' subscription='unconfigured'>


<subscribe-options>


<required/>


</subscribe-options>


</subscription>


</pubsub>


</iq>

{code}


注意: 只有订阅者在收到任何通知之前必须配置订阅,节点才应该包含这个<required/>子元素. 如果配置是必需的而配置请求没有在合理的时间内提交,一个服务可以(MAY)判定订阅请求超时(取决于服务或节点的配置).


同样的, 如果没有同步的配置就不能新建这个订阅, 服务可以(MAY)返回一个<not-acceptable/> 错误, 表示发生了一个pubsub-specific <configuration-required/>错误条件.


__案例 43. 服务返回错误说明需要配置订阅__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscribe node='princely_musings' jid='francisco@denmark.lit'/>


<options node='princely_musings' jid='francisco@denmark.lit'>


<x xmlns='jabber:x:data' type='submit'>


<field var='FORM_TYPE' type='hidden'>


<value>>>http://jabber.org/protocol/pubsub#subscribe_options</value>


</field>


<field var='pubsub#deliver'><value>1</value></field>


<field var='pubsub#digest'><value>0</value></field>


<field var='pubsub#include_body'><value>false</value></field>


<field var='pubsub#show-values'>


<value>chat</value>


<value>online</value>


<value>away</value>


</field>


</x>


</options>


</pubsub>


<error type='modify'>


<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


<configuration-required xmlns='http://jabber.org/protocol/pubsub#errors'/>


</error>


</iq>

{code}


如果没有包含<required/>元素也没有错误返回, 订阅立刻生效并且实体可以在任何时间配置这个订阅(服务可以(MAY)通过在IQ-result中包含一个空的<subscribe- options/>元素指出支持订阅选项, 如下案例所示).


__案例 44. 服务应答成功并指出支持订阅配置但不是必需的__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<subscription node='princely_musings' jid='francisco@denmark.lit' subscription='unconfigured'>


<subscribe-options/>


</subscription>


</pubsub>


</iq>

{code}


__6.2 从一个节点取消订阅__ {anchor:从一个节点取消订阅}


为了从一个节点取消订阅, 订阅者发送一个 IQ-set, 它的 <pubsub/> 子元素包含一个<unsubscribe/>元素,指明节点和已订阅的 JID.


__案例 45. 实体从一个节点取消订阅__


{code:xml}

<iq type='set'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='unsub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<unsubscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


</iq>

{code}


如果请求可以被成功处理,服务必须(MUST)一个 IQ result.


__案例 46. 服务应答成功__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='unsub1'/>

{code}


有很多原因可能导致取消订阅失败:


  1. 请求实体有多个订阅指向节点但未指定一个订阅ID.
  1. 请求未指定一个已存在的订阅者.
  1. 请求实体没有足够的权限取消指定JID的订阅.
  1. 节点不存在.
  1. 请求指定的订阅ID不合法或不是当前的.


更多的错误情景描述如下.


如果请求实体有多个订阅指向节点但是没有指定一个订阅ID, 服务必须(MUST)返回一个<bad-request/>错误, 它也应该(SHOULD)包含一个 <subid-required/>的pubsub-specific错误条件 .


__案例 47. 实体未指定SubID__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='unsub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<unsubscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='modify'>


<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


<subid-required xmlns='http://jabber.org/protocol/pubsub#errors'/>


</error>


</iq>

{code}


如果'jid'属性的值未指定一个已存在的订阅者, pubsub服务必须(MUST)返回一个错误节, 它应该(SHOULD)是<unexpected-request/>并且也应该(SHOULD)包含一个 <not-subscribed/>的pubsub-specific错误条件.


__案例 48. 请求实体不是一个订阅者__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='unsub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<unsubscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='cancel'>


<unexpected-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


<not-subscribed xmlns='http://jabber.org/protocol/pubsub#errors'/>


</error>


</iq>

{code}


如果请求实体被禁止取消特定JID的订阅, 服务必须(MUST)返回一个<forbidden/>错误. 服务必须(MUST)检查这个做出请求的实体是否被授权可以取消订阅. 如果订阅者的JID格式是<node@domain.tld/resource>, 服务必须(MUST)通过比较两个JID的<node@domain.tld>部分执行这个检查以确保它们是吻合的. 如果这些JID的纯JID部分不吻合并且请求实体没有被授权取消这个JID的订阅(例如, 因为它不是一个服务管理员或被授权的代理), 服务必须(MUST)返回一个<forbidden/>错误.


__案例 49. 请求实体被禁止取消订阅实体__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='unsub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<unsubscribe node='princely_musings' jid='bard@shakespeare.lit'/>


</pubsub>


<error type='auth'>


<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


</error>


</iq>

{code}


如果节点不存在, pubsub服务必须(MUST)返回一个 <item-not-found/> 错误.


__案例 50. 节点不存在__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='unsub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<unsubscribe node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='cancel'>


<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


</error>


</iq>

{code}


如果一个订阅标识符关联于某个订阅项, 取消订阅请求必须(MUST)包含一个适当的'subid'属性. 如果这个取消订阅请求包含一个 SubID 但是节点不支持 SubIDs (或订阅者第一次并没有使用 SubID 来订阅), 服务应该(SHOULD)忽略这个 SubID 并简单地取消订阅这个实体. 如果订阅者以前使用一个 SubID 来订阅但是取消订阅申请包含一个不合法或非当前订阅者的 SubID , 服务必须(MUST)返回一个<not-acceptable/>错误, 它应该(SHOULD)也包含一个<invalid-subid/>的pubsub-specific错误条件.


__案例 51. 非法的订阅项标识符__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='unsub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<unsubscribe node='princely_musings' subid='ba49252aaa4f5d320c24d3766f0bdcade78c78d3' jid='francisco@denmark.lit'/>


</pubsub>


<error type='modify'>


<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


<invalid-subid xmlns='http://jabber.org/protocol/pubsub#errors'/>


</error>


</iq>

{code}


__6.3 配置订阅选项__ {anchor:配置订阅选项}


实现可以(MAY)允许订阅者们配置订阅选项. 实现应该(SHOULD)使用数据表单(Data Forms)协议来实现这个配置(无论如何, 一个带外机制如web界面也可能被提供).


如果一个服务支持订阅选项, 它必须(MUST)在它对"disco#info"查询的应答中声明(在应答中包含一个feature,其'var'属性为"pubsub#subscription-options").


__案例 52. Pubsub服务显示对订阅选项的支持__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='feature1'>


<query xmlns='http://jabber.org/protocol/disco#info'>


...


<feature var='http://jabber.org/protocol/pubsub#subscription-options'/>


...


</query>


</iq>

{code}


一个订阅者通过在IQ-set节中包含一个<options/>元素来请求订阅选项.


__案例 53. 订阅者请求订阅选项表单__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='options1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<options node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


</iq>

{code}


如果请求被成功的处理, 服务必须(MUST)应答选项.


__案例 54. 服务应答选项表单__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='options1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


<options node='princely_musings' jid='francisco@denmark.lit'>


<x xmlns='jabber:x:data' type='form'>


<field var='FORM_TYPE' type='hidden'>


<value>>>http://jabber.org/protocol/pubsub#subscribe_options</value>


</field>


<field var='pubsub#deliver' type='boolean' label='Enable delivery?'>


<value>1</value>


</field>


<field var='pubsub#digest' type='boolean' label='Receive digest notifications (approx. one per day)?'>


<value>0</value>


</field>


<field var='pubsub#include_body' type='boolean' label='Receive message body in addition to payload?'>


<value>false</value>


</field>


<field var='pubsub#show-values' type='list-multi' label='Select the presence types which are allowed to receive notifications'>


<option label='Want to Chat'><value>chat</value></option>


<option label='Available'><value>online</value></option>


<option label='Away'><value>away</value></option>


<option label='Extended Away'><value>xa</value></option>


<option label='Do Not Disturb'><value>dnd</value></option>


<value>chat</value>


<value>online</value>


</field>


</x>


</options>


</pubsub>


</iq>

{code}


注意: 前述的例子展示了一些(但不是所有)的可能(MAY)被提供的配置选项. 如果一个实现使用数据表单(Data Forms)协议提供了这些选项, 它必须(MUST)使用那些在和'http://jabber.org/protocol/pubsub'名字空间关联的XMPP Registrar中注册了的字段(以上初步展示了那些字段, 并且在本文的 pubsub#subscribe_options FORM_TYPE 章节也描述了它们, 但是不能(MUST NOT)被当作规范, 因为 XMPP Registrar 以后还可以在不改变本文的情况下标准化更多的字段).


注意: 很多相关的数据表单字段有一个 "boolean" 类型并且必须(MUST)被有效处理. [16]


很多原因可以导致选项请求失败:


  1. 请求实体没有足够的权限来修改指定的JID的订阅选项.
  1. 请求实体(或指定的订阅者)未曾订阅.
  1. 请求没有同时指定 NodeID 和订阅者的 JID.
  1. 请求没有指定一个订阅项ID但是它被需要.
  1. 请求指定了一个订阅项ID但不是合法的或当前的.
  1. 订阅选项不知吃.
  1. 节点不存在.


更多的错误案例描述如下.


请求订阅选项的时候, 订阅者必须(MUST)指定向节点订阅的 JID 并且应该(SHOULD)指定一个节点(如果没有指定节点, 服务必须(MUST)认为请求实体希望为它的订阅项向根集合节点请求订阅选项; 详见本文的根集合节点章节).


服务必须(MUST)验证提出请求的实体已经被授权为订阅的实体设置订阅选项. 如果订阅者的JID的格式是<node@domain.tld/resource>, 服务必须(MUST)比较两个JID的<node@domain.tld>部分以确保他们是吻合的. 如果两个JID的纯JID部分不吻合并且请求实体没有被授权修改这个JID的订阅选项(例如, 因为它不是一个服务范围内的管理员或授权代理), 服务必须(MUST)返回一个<forbidden/>错误.


__案例 55. 请求实体没有足够的权限修改订阅选项__


{code:xml}

<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


 <options node='princely_musings' jid='bernardo@denmark.lit'/>


</pubsub>


<error type='auth'>


 <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> 


</error> 


</iq>

{code}


如果请求实体(或指定的订阅者, 如果不同的话) 未曾订阅, 服务必须(MUST)返回一个 <unexpected-request/> 错误, 它(SHOULD)也包括一个 <not-subscribed/> 的 pubsub-specific 错误条件.


__案例 56. 没有这个订阅者__


{code:xml}

<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='options1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'> 


 <options/> 


</pubsub> 


<error type='modify'> 


 <unexpected-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> 


 <not-subscribed xmlns='http://jabber.org/protocol/pubsub#errors'/> 


</error> 


</iq>

{code}


如果订阅者没有指定一个JID, 服务必须(MUST)返回一个<bad-request/>错误, 它也应该(SHOULD)包含一个<jid-required/>的pubsub-specific错误条件.


__案例 57. 订阅者JID未指定__


{code:xml}

<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='options1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


 <options/> 


</pubsub> 


<error type='modify'>


 <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


 <jid-required xmlns='http://jabber.org/protocol/pubsub#errors'/>


</error> 


</iq>

{code}


如果一个订阅项标识符关联于某个订阅项, 为了服务能够区分来自同一实体的订阅,在订阅请求中必须(MUST)带上'subid'属性. 如果'subid'是必需的但未被提供, 服务必须(MUST)返回一个<bad-request/>错误, 它也应该(SHOULD)包含一个<subid-required/>的pubsub-specific错误条件.


__案例 58. 需要SubID__


{code:xml}

<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


 <options node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub> <error type='modify'>


 <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


 <subid-required xmlns='http://jabber.org/protocol/pubsub#errors'/>


</error> 


</iq>

{code}


如果一个订阅项标识符关联于某订阅项, 但请求包含的 SubID 不合法或不是当前订阅者的, 服务必须(MUST)返回一个<not-acceptable/>错误, 它也应该(SHOULD)包含一个<invalid-subid/>的pubsub-specific错误条件.


__案例 59. 非法的订阅项标识符__


{code:xml}

<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='unsub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


 <unsubscribe node='princely_musings' subid='991d7fd1616fd041015064133cd097a10030819e' jid='francisco@denmark.lit'/>      


</pubsub>


<error type='modify'>


 <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


 <invalid-subid xmlns='http://jabber.org/protocol/pubsub#errors'/>


</error> 


</iq>

{code}


如果节点或服务不支持订阅选项, 服务必须(MUST)应答一个<feature-not-implemented/>错误, 指定一个<unsupported/>的pubsub-specific错误条件和一个"subscription-options"特性.


__案例 60. 订阅选项不支持__


{code:xml}

<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='options1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


 <options node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='cancel'>


 <feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> 


 <unsupported xmlns='http://jabber.org/protocol/pubsub#errors' feature='subscription-options'/>


</error> 


</iq>

{code}


如果节点不存在, pubsub服务必须(MUST)返回一个<item-not-found/>错误.


__案例 61. 节点不存在__


{code:xml}

<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='options1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


 <options node='princely_musings' jid='francisco@denmark.lit'/>


</pubsub>


<error type='cancel'>


 <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


</error> 


</iq>

{code}


接收了配置表单之后, 请求实体应该(SHOULD)提交这个表单来更新这个实体对于那个节点的订阅选项.


__案例 62. 订阅者提交完整的选项表单__


{code:xml}

<iq type='set' from='francisco@denmark.lit/barracks' to='pubsub.shakespeare.lit' id='options2'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


 <options node='princely_musings' jid='francisco@denmark.lit'>


  <x xmlns='jabber:x:data' type='submit'>


   <field var='FORM_TYPE' type='hidden'> 


    <value>http://jabber.org/protocol/pubsub#subscribe_options</value>


   </field>


   <field var='pubsub#deliver'>


    <value>1</value>


   </field>


   <field var='pubsub#digest'>


    <value>0</value>


   </field>


   <field var='pubsub#include_body'>


    <value>false</value>


   </field>


   <field var='pubsub#show-values'> 


    <value>chat</value> 


    <value>online</value> 


    <value>away</value>


   </field>


  </x>


 </options>


</pubsub>


</iq>

{code}


如果服务能成功处理提交的表单, 它必须(MUST)应答成功.


__案例 63. 服务应答成功__


{code:xml}

<iq type='result' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='options2'/>

{code}


如果订阅者尝试设置非法的选项组, 服务必须(MUST)应答一个<bad-request/>错误.


__案例 64. 服务对于非法选项应答错误请求__


{code:xml}

<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='options2'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'>


 <options node='princely_musings' jid='francisco@denmark.lit'>


  <x xmlns='jabber:x:data'>


   <field var='FORM_TYPE' type='hidden'> 


    <value>http://jabber.org/protocol/pubsub#subscribe_options</value>


   </field>


   <field var='pubsub#deliver'>


    <value>1</value>


   </field> 


   <field var='pubsub#digest'>


    <value>0</value>


   </field> 


   <field var='pubsub#include_body'>


    <value>false</value>


   </field> 


   <field var='pubsub#show-values'> 


    <value>chat</value> 


    <value>online</value> 


    <value>away</value> 


   </field> 


  </x> 


 </options> 


</pubsub> 


<error type='modify'> 


 <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> 


 <invalid-options xmlns='http://jabber.org/protocol/pubsub#errors'/> 


</error>


</iq>

{code}


其他适用于获取订阅选项时发生的错误也同样适用于设置订阅选项的情形.


大家直到, 如果一个服务支持订阅选项, 一个实体可以(MAY)在同一个节中订阅和提供订阅选项.


主意: <options/>元素必须(MUST)跟随在<subscribe/>元素之后并且不能(MUST NOT)拥有一个'node'属性或'jid'属性, 因为<subscribe/>元素的'node'属性值指明了期望的NodeID并且<subscribe/>元素的'jid'属性值指明了订阅者的JID; 如果这些值中的任何一个违规了, 服务必须(MUST)返回一个<bad-request/>错误.


__案例 65. 实体订阅一个节点并且设置配置选项__


{code:xml}

<iq type='set' from='francisco@denmark.lit/barracks' to='pubsub.shakespeare.lit' id='sub1'>


<pubsub xmlns='http://jabber.org/protocol/pubsub'> 


 <subscribe node='princely_musings' jid='francisco@denmark.lit'/> 


  <options> 


   <x xmlns='jabber:x:data'> 


    <field var='FORM_TYPE' type='hidden'> 


     <value>http://jabber.org/protocol/pubsub#subscribe_options</value> 


    </field> 


    <field var='pubsub#deliver'>


     <value>1</value>


    </field> 


    <field var='pubsub#digest'>


     <value>0</value>


    </field> 


    <field var='pubsub#include_body'>


     <value>false</value>


    </field> 


    <field var='pubsub#show-values'> 


     <value>chat</value> 


     <value>online</value> 


     <value>away</value> 


    </field> 


   </x> 


  </options> 


</pubsub> 


</iq>

{code}


__6.4 从节点接收条目__ {anchor:从节点接收条目}


选择保留条目的pubsub实现可以(MAY)允许实体从一个节点请求已有的条目(例如, 一个实体可能希望在成功订阅之后这样做以接收这个节点历史上发行的所有条目). 服务必须(MUST)遵守节点访问模式来决定是否向请求它们的实体返回这些条目. 具体来说:


   * 如果访问模式是"open", 服务应该(SHOULD)允许任何实体(无论是否订阅)接收条目.
   * 如果访问模式是"presence", 服务应该(SHOULD)允许任何已订阅这个所有者的出席信息的实体接收条目.
   * 如果访问模式是"roster", 服务应该(SHOULD)允许任何已订阅这个所有者的出席信息并处于适当的名册组中的实体接收条目.
   * 如果访问模式是"authorize"或"whitelist", 服务必须(MUST)只允许已订阅的实体来接收条目.


对于将来的访问模式所应有(SHOULD)的需求, 可能的例外是强制本地隐私和安全策略, 更全面的描述见本文的安全事项章节. (另外, 一个服务应该(MUST)总是允许节点所有者从一个节点接收条目并且应该(SHOULD)总是允许一个发行者这样做.)


订阅者可以通过仅仅不加限制地指明节点ID来请求所有的条目.


__案例 66. 订阅者请求所有条目__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


</iq>

{code}


服务然后应该(SHOULD)返回所有发行到这个节点的条目, 尽管它可以(MAY)截取结果(如果已发行的条目数量太多的话).


__案例 67. 服务返回所有条目__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'>


     <item id='368866411b877c30064a5f62b917cffe'>


       <entry xmlns='http://www.w3.org/2005/Atom'>


         <title>The Uses of This World</title>


         <summary>


O, that this too too solid flesh would melt

Thaw and resolve itself into a dew!


         </summary>


         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>


         <id>tag:denmark.lit,2003:entry-32396</id>


         <published>2003-12-12T17:47:23Z</published>


         <updated>2003-12-12T17:47:23Z</updated>


       </entry>


     </item>


     <item id='3300659945416e274474e469a1f0154c'>


       <entry xmlns='http://www.w3.org/2005/Atom'>


         <title>Ghostly Encounters</title>


         <summary>


O all you host of heaven! O earth! what else?

And shall I couple hell? O, fie! Hold, hold, my heart;

And you, my sinews, grow not instant old,

But bear me stiffly up. Remember thee!


         </summary>


         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>


         <id>tag:denmark.lit,2003:entry-32396</id>


         <published>2003-12-12T23:21:34Z</published>


         <updated>2003-12-12T23:21:34Z</updated>


       </entry>


     </item>


     <item id='4e30f35051b7b8b42abe083742187228'>


       <entry xmlns='http://www.w3.org/2005/Atom'>


         <title>Alone</title>


         <summary>


Now I am alone.

O, what a rogue and peasant slave am I!


         </summary>


         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>


         <id>tag:denmark.lit,2003:entry-32396</id>


         <published>2003-12-13T11:09:53Z</published>


         <updated>2003-12-13T11:09:53Z</updated>


       </entry>


     </item>


     <item id='ae890ac52d0df67ed7cfdf51b644e901'>


       <entry xmlns='http://www.w3.org/2005/Atom'>


         <title>Soliloquy</title>


         <summary>


To be, or not to be: that is the question:

Whether 'tis nobler in the mind to suffer

The slings and arrows of outrageous fortune,

Or to take arms against a sea of troubles,

And by opposing end them?


         </summary>


         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>


         <id>tag:denmark.lit,2003:entry-32397</id>


         <published>2003-12-13T18:30:02Z</published>


         <updated>2003-12-13T18:30:02Z</updated>


       </entry>


     </item>


   </items>


 </pubsub>


</iq>

{code}


即使服务或节点不支持持久化条目, 它也可以(MAY)返回最后发行的条目.


__案例 68. 服务返回最后发行的条目__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'>


     <item id='ae890ac52d0df67ed7cfdf51b644e901'>


       <entry xmlns='http://www.w3.org/2005/Atom'>


         <title>Soliloquy</title>


         <summary>


To be, or not to be: that is the question:

Whether 'tis nobler in the mind to suffer

The slings and arrows of outrageous fortune,

Or to take arms against a sea of troubles,

And by opposing end them?


         </summary>


         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>


         <id>tag:denmark.lit,2003:entry-32397</id>


         <published>2003-12-13T18:30:02Z</published>


         <updated>2003-12-13T18:30:02Z</updated>


       </entry>


     </item>


   </items>


 </pubsub>


</iq>

{code}


有很多种原因可能导致条目接收请求失败:


  1. 请求实体对同一个节点有多个订阅项但是没有指定一个订阅项ID.
  1. 请求实体订阅了但是指定了一个非法的订阅项ID.
  1. 节点没有返回条目给未订阅的实体但是请求实体未曾订阅.
  1. 服务或节点不支持持久条目并且没有返回最后发行的条目.
  1. 服务或节点不支持条目接收.
  1. 节点有一个"presence"访问模式而请求实体没有订阅所有者的出席信息.
  1. 节点有一个"roster"访问模式而请求实体不在授权的名册组中.
  1. 节点有一个"whitelist"访问模式而请求实体不在白名单中.
  1. 服务或节点需要付费才允许接收条目.
  1. 请求实体被屏蔽了从节点接收条目的功能(例如, 因为有一个排斥者的从属关系).
  1. 节点不存在.


这些错误完整描述如下.


如果请求实体对同一个节点有多个订阅项但是没有指定一个订阅项ID, 服务必须(MUST)返回一个<bad-request/>错误给订阅者, 它也应该(SHOULD)包含一个<subid-required/>的pubsub-specific错误条件.


__案例 69. 实体未指定SubID__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


 <error type='modify'>


   <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


   <subid-required xmlns='http://jabber.org/protocol/pubsub#errors'/>


 </error>


</iq>

{code}


如果请求实体订阅了但是指定了一个非法的订阅项ID, 服务必须(MUST)返回一个<not-acceptable/>错误给订阅者, 它也应该(SHOULD)包含一个<invalid-subid/>的pubsub-specific错误条件.


__案例 70. 实体制定了非法的SubID__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


 <error type='modify'>


   <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


   <invalid-subid xmlns='http://jabber.org/protocol/pubsub#errors'/>


 </error>


</iq>

{code}


如果节点未返回条目给未订阅的实体并且请求实体未曾订阅(包含已有一个未决的订阅项的情形), 服务必须(MUST)返回一个<not-authorized/>错误给订阅者, 它也应该(SHOULD)包含一个<not-subscribed/>的pubsub-specific错误条件.


__案例 71. 实体未订阅__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


 <error type='auth'>


   <not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


   <not-subscribed xmlns='http://jabber.org/protocol/pubsub#errors'/>


 </error>


</iq>

{code}


如果服务或节点不支持持久条目且没有返回最后发行的条目, 服务必须(MUST)返回一个<feature-not-implemented/>错误给订阅者, 指定一个pubsub-specific错误条件<unsupported/>以及一个特性"persistent-items".


__案例 72. 不支持持久条目__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


 <error type='cancel'>


   <feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


   <unsupported xmlns='http://jabber.org/protocol/pubsub#errors'
                feature='persistent-items'/>


 </error>


</iq>

{code}


如果服务或节点不支持接收条目(例如, 因为节点是一个集合节点), 服务必须(MUST)返回一个<feature-not-implemented/>错误给订阅者, 指明一个pubsub-specific错误条件<unsupported/>以及一个特性"retrieve-items".


__案例 73. 不支持条目接收__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


 <error type='cancel'>


   <feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


   <unsupported xmlns='http://jabber.org/protocol/pubsub#errors'
                feature='retrieve-items'/>


 </error>


</iq>

{code}


对于访问模式为"presence"的节点, 如果请求实体没有订阅所有者的出席信息那么pubsub服务必须(MUST)应答一个<not-authorized/>错误, 它还应该(SHOULD)包含一个pubsub-specific错误条件<presence-subscription-required/>.


__案例 74. 实体没有被授权接收条目(要求订阅出席信息)__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


 <error type='auth'>


   <not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


   <presence-subscription-required xmlns='http://jabber.org/protocol/pubsub#errors'/>


 </error>


</iq>

{code}


对于访问模式为"roster"的节点, 如果请求实体不在授权名册组中那么pubsub服务必须(MUST)应答一个<not-authorized/>错误, 它也应该(SHOULD)包含一个pubsub-specific错误条件<not-in-roster-group/>.


__案例 75. 实体没有被授权接收条目(不在名册组中)__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


 <error type='auth'>


   <not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


   <not-in-roster-group xmlns='http://jabber.org/protocol/pubsub#errors'/>


 </error>


</iq>

{code}


对于访问模式为"whitelist"的节点, 如果请求实体不在白名单中那么服务必须(MUST)返回一个<not-allowed/>错误, 指明一个pubsub-specific错误条件<closed-node/>.


__案例 76. 节点有白名单模式__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


 <error type='cancel'>


   <not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


   <closed-node xmlns='http://jabber.org/protocol/pubsub#errors'/>


 </error>


</iq>

{code}


商业开发可能希望把订阅者链接到一个付费客户数据库. 如果订阅者需要付费才能从那个节点接收条目(例如, 如果订阅者不在客户数据库或客户的帐目没有付清), 服务应该(SHOULD)返回一个<payment-required/>错误给订阅者.


__案例 77. 需要付费才能接收条目__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


 <error type='auth'>


   <payment-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


 </error>


</iq>

{code}


如果请求实体被屏蔽订阅(例如, 因为有一个被排斥者的从属关系), 服务必须(MUST)返回一个<forbidden/>错误给订阅者.


__案例 78. 请求实体被屏蔽__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


 <error type='auth'>


   <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


 </error>


</iq>

{code}


如果节点不存在, 服务应该(SHOULD)返回一个<item-not-found/>错误给订阅者.


__案例 79. 节点不存在__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items1'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


 <error type='cancel'>


   <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


 </error>


</iq>

{code}


一个服务可能(MAY)允许实体请求最近的N个条目(使用'max_items'属性). 当 max_items 被使用, 实现应该(SHOULD)返回N个最新的(反之则是N个最旧的)条目. (注意: 一个本协议的未来版本可能建议使用结果集管理Result Set Management \[17\] 替代'max_items'属性.)


__案例 80. 订阅者请求两个最新的条目__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='items2'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings' max_items='2'/>


 </pubsub>


</iq>

{code}


__案例 81. 服务返回最新的两个条目__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   to='francisco@denmark.lit/barracks'
   id='items2'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'>


     <item id='4e30f35051b7b8b42abe083742187228'>


       <entry xmlns='http://www.w3.org/2005/Atom'>


         <title>Alone</title>


         <summary>


Now I am alone.

O, what a rogue and peasant slave am I!


         </summary>


         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>


         <id>tag:denmark.lit,2003:entry-32396</id>


         <published>2003-12-13T11:09:53Z</published>


         <updated>2003-12-13T11:09:53Z</updated>


       </entry>


     </item>


     <item id='ae890ac52d0df67ed7cfdf51b644e901'>


       <entry xmlns='http://www.w3.org/2005/Atom'>


         <title>Soliloquy</title>


         <summary>


To be, or not to be: that is the question:

Whether 'tis nobler in the mind to suffer

The slings and arrows of outrageous fortune,

Or to take arms against a sea of troubles,

And by opposing end them?


         </summary>


         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>


         <id>tag:denmark.lit,2003:entry-32397</id>


         <published>2003-12-13T18:30:02Z</published>


         <updated>2003-12-13T18:30:02Z</updated>


       </entry>


     </item>


   </items>


 </pubsub>


</iq>

{code}


服务可以(MAY)返回事件通知而不是载荷(例如, 为了节省带宽). 如果这样, 客户端为了接收载荷可以(MAY)请求一个指定的条目(使用ItemID). 当一个实体通过ItemID来请求条目, 实现必须(MUST)允许在请求中指定多个条目.


__案例 82. 订阅者通过ItemID请求特定的条目__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='items3'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'>


     <item id='368866411b877c30064a5f62b917cffe'/>


     <item id='4e30f35051b7b8b42abe083742187228'/>


   </items>


 </pubsub>


</iq>

{code}


__案例 83. 服务发送请求的条目__


{code:xml}

<iq type='result'

   from='pubsub.shakespeare.lit'
   id='items3'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'>


     <item id='368866411b877c30064a5f62b917cffe'>


       <entry xmlns='http://www.w3.org/2005/Atom'>


         <title>The Uses of This World</title>


         <summary>


O, that this too too solid flesh would melt

Thaw and resolve itself into a dew!


         </summary>


         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>


         <id>tag:denmark.lit,2003:entry-32396</id>


         <published>2003-12-12T17:47:23Z</published>


         <updated>2003-12-12T17:47:23Z</updated>


       </entry>


     </item>


     <item id='4e30f35051b7b8b42abe083742187228'>


       <entry xmlns='http://www.w3.org/2005/Atom'>


         <title>Alone</title>


         <summary>


Now I am alone.

O, what a rogue and peasant slave am I!


         </summary>


         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>


         <id>tag:denmark.lit,2003:entry-32396</id>


         <published>2003-12-13T11:09:53Z</published>


         <updated>2003-12-13T11:09:53Z</updated>


       </entry>


     </item>


   </items>


 </pubsub>


</iq>

{code}


如果一个订阅项标识符和某个特定的订阅项相关, 服务必须(MUST)要求它, 这样它能基于和这一特定的订阅项相关的订阅选项来生成不同套的条目. 所以实体作出请求的时候必须(MUST)在itmes元素中包含'subid'属性; 如果它没有这样做, 服务必须(MUST)返回一个<not-acceptable/>错误, 指明一个pubsub-specific错误条件<subid-required/>.


__案例 84. 订阅者不带SubID发送请求__


{code:xml}

<iq type='get'

   from='francisco@denmark.lit/barracks'
   to='pubsub.shakespeare.lit'
   id='items5'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


</iq>

{code}


__案例 85. 要求SubID__


{code:xml}

<iq type='error'

   from='pubsub.shakespeare.lit'
   id='items5'>


 <pubsub xmlns='http://jabber.org/protocol/pubsub'>


   <items node='princely_musings'/>


 </pubsub>


 <error type='modify'>


   <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>


   <subid-required xmlns='http://jabber.org/protocol/pubsub#errors'/>


 </error>


</iq>

{code}


__7. 发行者用例__ {anchor:发行者用例}


__7.1 向一个节点发行一个条目__ {anchor:向一个节点发行一个条目}


任何被允许向一个节点发行条目的实体 (也就是说.,一个发行者或一个所有者) 可以通过发送一个包含<publish/>子元素的 IQ-set 给服务来做到这一点; 这个 <publish/> 元素必须( MUST)拥有一个 'node' 属性并且根据这个节点配置可以(MAY)不包含 <item/>元素, 一个 <item/> 元素, 或 (用于批量处理)多个 <item/> 元素.


注意: 为触发一个通知不必要在发行请求中包含载荷或甚至一个 <item/> 元素. 例如, 发行到一个临时的仅用于通知的节点的结果将是一个不包含任何 <item/> 元素的通知 (如本文的Motivating Example章节所示). However, for the sake of convenience we refer to the act of publication as "publishing an item" (rather than, say, "triggering a notification") even though a publication request will not always contain an <item/> element.


Example 86. Publisher publishes an item with an ItemID


<iq type='set'

   from='hamlet@denmark.lit/blogbot'
   to='pubsub.shakespeare.lit'
   id='publish1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <publish node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'>
       <entry xmlns='http://www.w3.org/2005/Atom'>
         <title>Soliloquy</title>
         <summary>

To be, or not to be: that is the question:

Whether 'tis nobler in the mind to suffer

The slings and arrows of outrageous fortune,

Or to take arms against a sea of troubles,

And by opposing end them?

         </summary>
         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>
         <id>tag:denmark.lit,2003:entry-32397</id>
         <published>2003-12-13T18:30:02Z</published>
         <updated>2003-12-13T18:30:02Z</updated>
       </entry>
     </item>
   </publish>
 </pubsub>

</iq>



If the pubsub service can successfully process the request, it MUST inform the publisher of success.


Example 87. Service replies with success


<iq type='result'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/blogbot'
   id='publish1'/>



If the pubsub service can successfully process the request, it MUST send then one <message/> stanza containing a pubsub event notification to each approved subscriber. Each <message/> stanza generated by a pubsub service SHOULD possess an 'id' attribute with a unique value so that the service can properly track any notification-related errors that may occur (see the Handling Notification-Related Errors section of this document).


Depending on the node configuration, the event notification either will or will not contain the payload, as shown in the following examples.


If the node is configured to include payloads, the subscribers will receive payloads with the event notifications.


Example 88. Subscribers receive event notifications with payloads


<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo'>

 <event xmlns='http://jabber.org/protocol/pubsub#event'>
   <items node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'>
       <entry xmlns='http://www.w3.org/2005/Atom'>
         <title>Soliloquy</title>
         <summary>

To be, or not to be: that is the question:

Whether 'tis nobler in the mind to suffer

The slings and arrows of outrageous fortune,

Or to take arms against a sea of troubles,

And by opposing end them?

         </summary>
         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>
         <id>tag:denmark.lit,2003:entry-32397</id>
         <published>2003-12-13T18:30:02Z</published>
         <updated>2003-12-13T18:30:02Z</updated>
       </entry>
     </item>
   </items>
 </event>

</message>


<message from='pubsub.shakespeare.lit' to='bernardo@denmark.lit' id='bar'>

 <event xmlns='http://jabber.org/protocol/pubsub#event'>
   <items node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'>
       <entry xmlns='http://www.w3.org/2005/Atom'>
         <title>Soliloquy</title>
         <summary>

To be, or not to be: that is the question:

Whether 'tis nobler in the mind to suffer

The slings and arrows of outrageous fortune,

Or to take arms against a sea of troubles,

And by opposing end them?

         </summary>
         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>
         <id>tag:denmark.lit,2003:entry-32397</id>
         <published>2003-12-13T18:30:02Z</published>
         <updated>2003-12-13T18:30:02Z</updated>
       </entry>
     </item>
   </items>
 </event>

</message>


<message from='pubsub.shakespeare.lit' to='horatio@denmark.lit' id='baz'>

 <event xmlns='http://jabber.org/protocol/pubsub#event'>
   <items node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'>
       <entry xmlns='http://www.w3.org/2005/Atom'>
         <title>Soliloquy</title>
         <summary>

To be, or not to be: that is the question:

Whether 'tis nobler in the mind to suffer

The slings and arrows of outrageous fortune,

Or to take arms against a sea of troubles,

And by opposing end them?

         </summary>
         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>
         <id>tag:denmark.lit,2003:entry-32397</id>
         <published>2003-12-13T18:30:02Z</published>
         <updated>2003-12-13T18:30:02Z</updated>
       </entry>
     </item>
   </items>
 </event>

</message>


<message from='pubsub.shakespeare.lit' to='marcellus@denmark.lit' id='fez'>

 <event xmlns='http://jabber.org/protocol/pubsub#event'>
   <items node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'>
       <entry xmlns='http://www.w3.org/2005/Atom'>
         <title>Soliloquy</title>
         <summary>

To be, or not to be: that is the question:

Whether 'tis nobler in the mind to suffer

The slings and arrows of outrageous fortune,

Or to take arms against a sea of troubles,

And by opposing end them?

         </summary>
         <link rel='alternate' type='text/html'
               href='http://denmark.lit/2003/12/13/atom03'/>
         <id>tag:denmark.lit,2003:entry-32397</id>
         <published>2003-12-13T18:30:02Z</published>
         <updated>2003-12-13T18:30:02Z</updated>
       </entry>
     </item>
   </items>
 </event>

</message>


.

.

.



If the node is configured to not include payloads, the subscribers will receive event notifications only. (If payloads are not included, subscribers may request the published item via the protocol defined in the Retrieve Items from a Node section of this document.)


Example 89. Subscribers receive event notifications only


<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo'>

 <event xmlns='http://jabber.org/protocol/pubsub#event'>
   <items node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </items>
 </event>

</message>


<message from='pubsub.shakespeare.lit' to='bernardo@denmark.lit' id='bar'>

 <event xmlns='http://jabber.org/protocol/pubsub#event'>
   <items node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </items>
 </event>

</message>


<message from='pubsub.shakespeare.lit' to='horatio@denmark.lit' id='baz'>

 <event xmlns='http://jabber.org/protocol/pubsub#event'>
   <items node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </items>
 </event>

</message>


<message from='pubsub.shakespeare.lit' to='marcellus@denmark.lit' id='fez'>

 <event xmlns='http://jabber.org/protocol/pubsub#event'>
   <items node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </items>
 </event>

</message>


.

.

.



If a single entity is subscribed to a node multiple times, the service SHOULD notate the event notification so that the entity can determine which subscription identifier(s) generated this event. If these notations are included, they MUST use the Stanza Headers and Internet Metadata [18] format and SHOULD be included after the event notification information (i.e., as the last child of the <message/> stanza).


Example 90. Subscriber receives notated event notification


<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo'>

 <event xmlns='http://jabber.org/protocol/pubsub#event'>
   <items node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </items>
 </event>
 <headers xmlns='http://jabber.org/protocol/shim'>
   <header name='pubsub#subid'>123-abc</header>
   <header name='pubsub#subid'>004-yyy</header>
 </headers>

</message>



There are several reasons why the publish request might fail:


  1. The requesting entity does not have sufficient privileges to publish.
  2. The node does not support item publication.
  3. The node does not exist.
  4. The payload size exceeds a service-defined limit.
  5. The item contains more than one payload element or the namespace of the root payload element does not match the configured namespace for the node.
  6. The request does not match the node configuration.


These error cases are described more fully below.


Note: If a publisher publishes an item with an Item ID and the ItemID matches that of an existing item, the pubsub service MUST NOT fail the publication but instead MUST overwrite the existing item and generate a new event notification (i.e., re-publication is equivalent to modification).


If the requesting entity does not have sufficient privileges to publish, the service MUST return a <forbidden/> error.


Example 91. Entity does not have sufficient privileges to publish to node


<iq type='error'

   from='pubsub.shakespeare.lit'
   id='publish1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <publish node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'>
       ... PAYLOAD ...
     </item>
   </publish>
 </pubsub>
 <error type='auth'>
   <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
 </error>

</iq>



If the node does not support item publication (because it is a Collection Node), the service MUST return a <feature-not-implemented/> error, specifying a pubsub-specific error condition of <unsupported/> and a feature of "publish".


Example 92. Node does not support item publication


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='publish1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <publish node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'>
       ... PAYLOAD ...
     </item>
   </publish>
 </pubsub>
 <error type='cancel'>
   <feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
   <unsupported xmlns='http://jabber.org/protocol/pubsub#errors'
                feature='publish'/>
 </error>

</iq>



If the requesting entity attempts to publish an item to a node that does not exist, the service MUST return an <item-not-found/> error.


Example 93. Entity attempts to publish to a non-existent node


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='publish1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <publish node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'>
       ... PAYLOAD ...
     </item>
   </publish>
 </pubsub>
 <error type='cancel'>
   <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
 </error>

</iq>



If the payload size exceeds a service-defined limit, the service MUST return a <not-acceptable/> error, which SHOULD also include a pubsub-specific error condition of <payload-too-big/>.


Example 94. Entity attempts to publish very large payload


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='publish1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <publish node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'>
       ... HUGE PAYLOAD ...
     </item>
   </publish>
 </pubsub>
 <error type='modify'>
   <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
   <payload-too-big xmlns='http://jabber.org/protocol/pubsub#errors'/>
 </error>

</iq>



If the <item/> element contains more than one payload element or the namespace of the root payload element does not match the configured namespace for the node, the service MUST bounce the request with a <bad-request/> error, which SHOULD also include a pubsub-specific error condition of <invalid-payload/>.


Example 95. Entity attempts to publish item with multiple payload elements or namespace does not match


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='publish1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <publish node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'>
       ... INVALID PAYLOAD ...
     </item>
   </publish>
 </pubsub>
 <error type='modify'>
   <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
   <invalid-payload xmlns='http://jabber.org/protocol/pubsub#errors'/>
 </error>

</iq>



If the request does not conform to the configured event type for the node, the service MAY bounce the request with a <bad-request/> error, which SHOULD also include a pubsub-specific error condition. The following rules apply:


   * If the event type is persistent (either notification or payload) and the publisher does not specify an ItemID, the service MUST generate the ItemID and MUST NOT bounce the publication request.
   * If the event type is persistent (either notification or payload) and the publisher does not include an item, the service MUST bounce the publication request with a <bad-request/> error and a pubsub-specific error condition of <item-required/>.
   * If the event type is payload (either persistent or transient) and the publisher does not include a payload, the service SHOULD bounce the publication request with a <bad-request/> error and a pubsub-specific error condition of <payload-required/>.
   * If the event type is notification + transient and the publisher provides an item, the service MUST bounce the publication request with a <bad-request/> error and a pubsub-specific error condition of <item-forbidden/>.


Examples of these errors are shown below.


Example 96. Publisher attempts to publish to persistent node with no item


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='publish1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <publish node='princely_musings'/>
 </pubsub>
 <error type='modify'>
   <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
   <item-required xmlns='http://jabber.org/protocol/pubsub#errors'/>
 </error>

</iq>



Example 97. Publisher attempts to publish to payload node with no payload


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='publish1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <publish node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </publish>
 </pubsub>
 <error type='modify'>
   <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
   <payload-required xmlns='http://jabber.org/protocol/pubsub#errors'/>
 </error>

</iq>



Example 98. Publisher attempts to publish to transient notification node with item


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='publish1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <publish node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </publish>
 </pubsub>
 <error type='modify'>
   <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
   <item-forbidden xmlns='http://jabber.org/protocol/pubsub#errors'/>
 </error>

</iq>



Finally, in order to facilitate authorization for item removal as described in the Delete an Item from a Node section of this document, implementations that support persistent items SHOULD store the item (if the node is so configured) and maintain a record of the publisher.

7.2 Delete an Item from a Node


A service SHOULD allow a publisher to delete an item once it has been published to a node that supports persistent items. To delete an item, the publisher sends a retract request as shown in the following examples. The <retract/> element MUST possess a 'node' attribute, MAY possess a 'notify' attribute, and SHOULD contain one <item/> element (but MAY contain more than one <item/> element for Batch Processing of item retractions); the <item/> element MUST be empty and MUST possess an 'id' attribute.


Example 99. Entity deletes an item from a node


<iq type='set'

   from='hamlet@denmark.lit/elsinore'
   to='pubsub.shakespeare.lit'
   id='retract1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <retract node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </retract>
 </pubsub>

</iq>



Example 100. Service replies with success


<iq type='result'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='retract1'/>



There are several reasons why the item retraction request might fail:


  1. The publisher does not have sufficient privileges to delete the requested item.
  2. The node or item does not exist.
  3. The request does not specify a node.
  4. The request does not include an <item/> element or the <item/> element does not specify an ItemID.
  5. The node does not support persistent items.
  6. The service does not support the deletion of items.


These error cases are described more fully below.


If the requesting entity does not have sufficient privileges to delete the item, the service MUST return a <forbidden/> error.


Example 101. Requesting entity does not have sufficient privileges


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='retract1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <retract node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </retract>
 </pubsub>
 <error type='auth'>
   <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
 </error>

</iq>



If the node or item does not exist, the service MUST return an <item-not-found/> error.


Example 102. Non-existent node or item


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='retract1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <retract node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </retract>
 </pubsub>
 <error type='cancel'>
   <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
 </error>

</iq>



If the request does not specify a node, the service MUST return a <bad-request/> error, which SHOULD also include a pubsub-specific error condition of <node-required/>.


Example 103. Request does not specify a node


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='retract1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <retract/>
 </pubsub>
 <error type='modify'>
   <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
   <node-required xmlns='http://jabber.org/protocol/pubsub#errors'/>
 </error>

</iq>



If the request does not include an <item/> element or the <item/> element does not specify an ItemID, the service MUST return a <bad-request/> error, which SHOULD also include a pubsub-specific error condition of <item-required/>.


Example 104. Request does not specify an item


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='retract1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <retract node='princely_musings'/>
 </pubsub>
 <error type='modify'>
   <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
   <item-required xmlns='http://jabber.org/protocol/pubsub#errors'/>
 </error>

</iq>



If the node does not support persistent items (e.g., because it is a collection node or a transient node that does not deliver payloads), the service MUST return a <feature-not-implemented/> error, specifying a pubsub-specific error condition of <unsupported/> and a feature of "persistent-items".


Example 105. Node does not support persistent items


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='retract1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <retract node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </retract>
 </pubsub>
 <error type='cancel'>
   <feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
   <unsupported xmlns='http://jabber.org/protocol/pubsub#errors'
                feature='persistent-items'/>
 </error>

</iq>



If the service does not support item deletion, it MUST return a <feature-not-implemented/> error, specifying a pubsub-specific error condition of <unsupported/> and a feature of "delete-nodes".


Example 106. Service does not support item deletion


<iq type='error'

   from='pubsub.shakespeare.lit'
   to='hamlet@denmark.lit/elsinore'
   id='retract1'>
 <pubsub xmlns='http://jabber.org/protocol/pubsub'>
   <retract node='princely_musings'>
     <item id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </retract>
 </pubsub>
 <error type='cancel'>
   <feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
   <unsupported xmlns='http://jabber.org/protocol/pubsub#errors'
                feature='delete-nodes'/>
 </error>

</iq>



If none of the foregoing errors occurred, then the service MUST delete the item.


If none of the foregoing errors occurred and the <retract/> element included a 'notify' attribute with a value of "true" or "1" [19], then the service MUST delete the item and MUST send message notifications to all subscribers as shown below. The syntax is identical to publish notifications except that instead of an <item/> element, the notification includes a <retract/> element.


Example 107. Subscribers are notified of deletion


<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo'>

 <event xmlns='http://jabber.org/protocol/pubsub#event'>
   <items node='princely_musings'>
     <retract id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </items>
 </event>

</message>


<message from='pubsub.shakespeare.lit' to='bernardo@denmark.lit' id='bar'>

 <event xmlns='http://jabber.org/protocol/pubsub#event'>
   <items node='princely_musings'>
     <retract id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </items>
 </event>

</message>


.

.

.



If a single entity is subscribed to the node multiple times, the service SHOULD notate the notification of item deletion so that the entity can determine which subscription identifier(s) generated this event. As above, if these notations are included, they MUST use the Stanza Headers and Internet Metadata (SHIM) protocol and SHOULD be included after the event notification information (i.e., as the last child of the <message/> stanza).


Example 108. Subscriber receives notated event notification


<message from='pubsub.shakespeare.lit' to='bernardo@denmark.lit' id='bar'>

 <event xmlns='http://jabber.org/protocol/pubsub#event'>
   <items node='princely_musings'>
     <retract id='ae890ac52d0df67ed7cfdf51b644e901'/>
   </items>
 </event>
 <headers xmlns='http://jabber.org/protocol/shim'>
   <header name='pubsub#subid'>123-abc</header>
   <header name='pubsub#subid'>004-yyy</header>
 </headers>

</message>



" 文档信息

系列: XEP

编号: 0060

发行者: XMPP标准基金会

状态: 草案

类型: 标准跟踪

版本: 1.9

最后更新日期: 2006-09-13

批准机构: XMPP理事会

依赖于: XMPP Core, XEP-0004, XEP-0030, XEP-0068, XEP-0082, XEP-0131

上文: 无

下文: 无

简称: pubsub

pubsub 名字空间的XML方案: <http://www.xmpp.org/schemas/pubsub.xsd>

pubsub#errors 名字空间的XML方案: <http://www.xmpp.org/schemas/pubsub-errors.xsd>

pubsub#event 名字空间的XML方案: <http://www.xmpp.org/schemas/pubsub-event.xsd>

pubsub#owner 名字空间的XML方案: <http://www.xmpp.org/schemas/pubsub-owner.xsd>

Wiki 页: <http://wiki.jabber.org/index.php/Publish-Subscribe%20(XEP-0060)>

作者信息

Peter Millard

作者介绍

Peter Saint-Andre

Email: stpeter@jabber.org
JID: [xmpp:stpeter@jabber.org stpeter@jabber.org]

Ralph Meijer

Email: ralphm@ik.nu
JID: [xmpp:ralphm@ik.nu ralphm@ik.nu]
个人工具