2. URN 语法
如上所述, 本规范中 URN 的语法所允许的功能比早期规范 (最近的是 [RFC2141]) 要多得多. 它也与通用 URI 语法 [RFC3986] 相协调 (必须指出, 该语法是在较早的 URN 规范之后完成的).
然而, 本规范并未扩展 URN 语法以允许直接使用 ASCII 范围 [RFC20] 之外的字符. 这一限制意味着任何此类字符都需要按 URI 规范 [RFC3986] 第 2.1 节所述进行百分号编码.
URN 的基本语法使用 [RFC5234] 规定的增强巴科斯范式 (Augmented Backus-Naur Form, ABNF) 定义. 此处未定义的规则 (具体而言: alphanum, fragment 和 pchar) 作为 URI 语法 [RFC3986] 的一部分定义, 在此使用它们是为了指出与那边所用术语之间的语法关系. 下文所用某些术语的定义并不全面; 额外的限制由本文档中针对这些术语的章节里的正文文字施加 (尤其是第 2.3.1 节中的 r-component 和第 2.3.2 节中的 q-component).
namestring = assigned-name
[ rq-components ]
[ "#" f-component ]
assigned-name = "urn" ":" NID ":" NSS
NID = (alphanum) 0*30(ldh) (alphanum)
ldh = alphanum / "-"
NSS = pchar *(pchar / "/")
rq-components = [ "?+" r-component ]
[ "?=" q-component ]
r-component = pchar *( pchar / "/" / "?" )
q-component = pchar *( pchar / "/" / "?" )
f-component = fragment
问号字符 "?" 在 r-component, q-component 和 f-component 内部可以不进行百分号编码而直接使用. 除这些组成部分内部之外, 一个并非紧接 "=" 或 "+" 的 "?" 对 URN 而言是未定义的, URN 专用的解析器和其他处理器应当 (SHOULD) 将其视为语法错误.
以下各节提供关于 URN 语法元素的附加信息.
2.1. 命名空间标识符 (NID)
NID 大小写不敏感 (例如, "ISBN" 与 "isbn" 等价).
NID 中不允许出现 ASCII 范围 [RFC20] 之外的字符, 也不支持针对此类字符的任何编码机制.
第 5.1 节和第 5.2 节对可用作 NID 的字符串施加了额外的约束, 也就是说, 上面所示的语法并不全面.
2.2. 命名空间特定字符串 (NSS)
NSS 是一个在某个 URN 命名空间内唯一的字符串, 它以一致的方式被分配和管理, 并符合相关 URN 命名空间的定义. NID (在整个 "urn" 方案中唯一) 与 NSS (在该 URN 命名空间内唯一) 的组合确保所得到的 URN 具有全局唯一性.
本文档所规定的 NSS 允许若干早期规范不允许的字符 (见附录 B). 特别是, 现在被允许的 "/" 字符实际上使得封装来自非 URN 标识符系统的层级名称成为可能. 例如, 设想一个假想的层级标识符系统, 其中的名称形如以 "/" 字符分隔的数字序列, 例如 "1/406/47452/2". 如果此类名称的权威机构使用 URN, 那么把既有名称放进 NSS 是很自然的, 从而得到诸如 "urn:example:1/406/47452/2" 这样的 URN.
NSS 语法的这些变化并不修改按照 [RFC2141] 定义的 URN 命名空间的编码规则. 如果任何此类 URN 命名空间 (其名称在 URN 上下文之外, 即在某个非 URN 标识符系统中使用) 在该标识符系统内也允许以原生形式使用 "/", "~" 或 "&", 那么本规范不改变该 URN 命名空间的编码规则.
取决于管辖某个非 URN 标识符系统及其关联 URN 命名空间的规则, 在该标识符系统中有效的名称可能包含上文引用的 "pchar" 产生式所不允许的字符 (例如 ASCII 范围之外的字符, 或者与 RFC 3986 中的限制一致, "/", "?", "#", "[" 和 "]" 这些字符). 虽然此类名称在该非 URN 标识符系统内可能有效, 但在它被转换为符合该特定 URN 命名空间规则的 NSS 之前, 它并不是有效的 URN. 对于由非 URN 标识符系统中单独存在的名称构成的 URN, 把名称从其 "原生" 格式转换为 URN 格式是通过使用为 URN 总体定义的规范化与编码方法, 或该 URN 命名空间的特定规则来完成的. 不了解命名空间特定规范化与编码规则的软件禁止 (MUST NOT) 从非 URN 标识符系统中的名称构造 URN.
特别是, 就 ASCII 范围之外的字符而言, 出现在协议中或在系统之间传递的 URN 必须 (MUST) 只使用以 UTF-8 编码并进一步按 RFC 3986 要求编码的 Unicode 字符. 在可行且与在别处定义并标准化的名称的要求以及第 1.2 节所讨论的原则一致的范围内, 用于表示名称的字符应当 (SHOULD) 限于 ASCII 字母和数字, 或者限于某些广泛使用的模型的字符与语法, 例如应用程序中国际化域名 (Internationalizing Domain Names in Applications, IDNA) [RFC5890], 国际化字符串的准备, 强制与比较 (Preparation, Enforcement, and Comparison of Internationalized Strings, PRECIS) [RFC7613], 或 Unicode 标识符与模式语法规范 [UAX31].
为了使 URN 在协议演进及其周围环境变化时尽可能稳定和持久, URN 命名空间不应 (SHOULD NOT) 允许 ASCII 范围 [RFC20] 之外的字符, 除非该特定 URN 命名空间的性质使此类字符成为必要.
2.3. 可选组成部分
本规范在 URN 语法中包含三个可选组成部分. 它们被称为 r-component, q-component 和 f-component, 下文将更详细地描述. 由于本规范几乎只关注 URN 语法, 它并未为一般 URN 定义这些组成部分的详细语义. 然而, 这些组成部分中的每一个都有其独立于任何给定 URN 及其 URN 命名空间的不同角色. 其意图是客户端能够对所有 URN 统一处理这些组成部分. 这些组成部分可以 (MAY) 用于来自现有 URN 命名空间的 URN, 无论某个 URN 命名空间是否显式支持它们. 然而, 与 RFC 3986 中所采取的做法一致, 对于某个 URN 命名空间或资源而言未定义或无意义的组成部分, 包含它们的 URN 的行为是未定义的. 以下各节更详细地描述这些可选组成部分及其解释.
2.3.1. r-component
r-component 旨在把参数传递给 URN 解析服务 (广义而言, 见第 1.2 节), 并由这些服务解释. (相比之下, 把参数传递给由 URN 标识的资源, 或传递给管理此类资源的应用程序, 则由下一节所述的 q-component 处理.)
URN 的 r-component 在任何其他已知 URI 方案中都没有语法上的对应物.
序列 "?+" 引入 r-component. r-component 以 "?=" 序列 (它开始一个 q-component) 或 "#" 字符 (井号, 它开始一个 f-component) 结束. 如果这两者都未出现, 则 r-component 一直延续到 URN 的末尾. 请注意, ASCII 范围 [RFC20] 之外的字符必须 (MUST) 使用通用 URI 规范 [RFC3986] 第 2.1 节所定义的方法进行百分号编码.
如第 3 节所述, 在确定 URN-Equivalence 时不得 (SHALL NOT) 考虑 r-component. 然而, 在向 URN 解析服务提出请求时, 必须 (SHALL) 随 URN 一起提供 r-component.
本文档只定义 r-component 的语法, 并将其保留供未来使用. r-component 的确切语义及其在 URN 解析协议中的使用, 属于可能在单独规范中标准化的议题, 这些规范想必会包括定义解析服务标识符的约定和注册表的规范.
考虑一个假想的例子: 向解析服务传递参数 (比如说, 传递一个 ISO alpha-2 国家代码 [ISO.3166-1], 以便选择在其中搜索某本书纸质副本的首选国家). 这或许可以通过在 r-component 中指定该国家代码来实现, 从而得到诸如以下的 URN:
urn:example:foo-bar-baz-qux?+CCResolve:cc=uk
尽管上述内容应当可以作为对 r-component 意图的一般性解释和说明, 但它们仍存在许多未决问题, 包括它们与注册时与特定 URN 命名空间相关联的解析机制之间的关系. 因此, 在 r-component 的语义被标准化之前, 不应 (SHOULD NOT) 将其用于 URN.
2.3.2. q-component
q-component 旨在把参数传递给所命名的资源或能够提供所请求服务的系统, 并由该资源或系统解释. (相比之下, 把参数传递给 URN 解析服务则由上一节所述的 r-component 处理.)
URN 的 q-component 与 URI 查询组成部分具有相同的语法, 但它由 "?=" 引入, 而不是单独由 "?" 引入. 对于可能被解析为某个作为定位符的 URI 的 URN, q-component 的语义与该 URI 查询组成部分的语义完全相同. 因此, 当 URN 解析器为带有 q-component 的 URN 返回一个作为定位符的 URI 时, 其做法是把 q-component 从 URN 复制到该 URI 的查询组成部分. 该复制操作的一个例子见下文.
当原始 URN 带有 q-component 且 URI 带有查询字符串时, 本规范并未规定在把 URN 解析为作为定位符的 URI 的情况下所要求的行为. 不同的情形可能需要不同的做法. 解析器应当 (SHOULD) 在此类情况下记录其策略.
如果 URN 并未解析为作为定位符的 URI, 则本规范未定义 q-component 的解释. 对于可能被解析为作为定位符的 URI 的 URN, q-component 的语义与对该 URI 所定位资源的查询的语义完全相同.
为了与 RFC 3986 保持一致, q-component 的一般语法和语义并非由该 URN 的 URN 命名空间所定义, 也不依赖于它. 与 RFC 3986 平行地, 语法和语义的具体细节 (例如哪些关键词或术语是有意义的) 当然可能取决于某个特定的 URN 命名空间, 甚至某个特定的资源.
序列 "?=" 引入 q-component. q-component 以 "#" 字符 (井号, 它开始一个 f-component) 结束. 如果该字符未出现, 则 q-component 一直延续到 URN 的末尾. 斜杠 ("/") 和问号 ("?") 字符可以表示 q-component 内的数据. 请注意, ASCII 范围 [RFC20] 之外的字符必须 (MUST) 使用通用 URI 规范 [RFC3986] 第 2.1 节所定义的方法进行百分号编码.
如第 3 节所述, 在确定 URN-Equivalence 时不得 (SHALL NOT) 考虑 q-component.
URN 命名空间及语法中相关信息的放置应当 (SHOULD) 设计成避免解析服务需要考虑 q-component 的任何必要性. 命名空间特定的以及更通用的解析系统禁止 (MUST NOT) 要求把 q-component 信息传递给它们进行处理.
考虑一个假想的例子: 向一个返回不同地区或不同时间段天气报告的应用程序传递参数. 这或许可以通过在该 URN 的 q-component 中指定纬度和经度坐标以及日期时间来实现, 从而得到如下所示的 URN.
urn:example:weather?=op=map&lat=39.56
&lon=-104.85&datetime=1969-07-21T02:56:15Z
如果这个例子解析为一个 HTTP URI, 结果可能如下所示:
https://weatherapp.example?op=map&lat=39.56
&lon=-104.85&datetime=1969-07-21T02:56:15Z
2.3.3. f-component
f-component 旨在由客户端解释为对所命名资源内部某个位置或某个区域的指定. 它区分由某个 URN 命名的资源的各个构成部分. 对于解析为一个或多个可解引用为表示的定位符的 URN, 或者 URN 解析器直接返回该资源表示的情形, f-component 的语义由该表示的媒体类型定义.
URN 的 f-component 与 URI 片段组成部分具有相同的语法. 如果包含 f-component 的 URN 解析为单个与该所命名资源关联的作为定位符的 URI, 那么来自该 URN 的 f-component 可以 (通常由客户端) 作为该 URI 的片段来应用. 如果 URN 并未解析为作为定位符的 URI, 则本规范未定义 f-component 的解释. 因此, 对于可能被解析为作为定位符的 URI 的 URN, f-component 的语义与针对该资源的片段的语义完全相同.
为了与 RFC 3986 保持一致, f-component 的一般语法和语义均不由该 URN 的 URN 命名空间所定义, 也不依赖于它. 与 RFC 3986 平行地, 语法和语义的具体细节 (例如哪些关键词或术语是有意义的) 当然可能取决于某个特定的 URN 命名空间, 甚至某个特定的资源.
f-component 由井号 ("#") 字符引入, 并由 URI 的末尾终止. 出现在 f-component 中的任何 ASCII 范围 [RFC20] 之外的字符必须 (MUST) 使用通用 URI 规范 [RFC3986] 第 2.1 节所定义的方法进行百分号编码.
如第 3 节所述, 在确定 URN-Equivalence 时不得 (SHALL NOT) 考虑 f-component.
客户端不应 (SHOULD NOT) 把 f-component 传递给解析服务, 除非这些服务也执行对象检索和解释功能.
考虑一个假想的例子: 获取作为某个更大实体之组成部分的资源 (比如一本书的各章). 每个部分都可以在 f-component 中指定, 从而得到诸如以下的 URN:
urn:example:foo-bar-baz-qux#somepart