# 4. 资源属性的数据模型
# 4.1 资源属性模型
属性是描述资源状态的数据片段。属性是关于数据的数据。
属性在分布式创作环境中使用,以提供有效的资源发现和管理能力。例如,“subject”属性可能允许按主题索引所有资源,而“author”属性可能用于发现哪个作者写了哪些文档。
DAV属性模型是一个键值对(一个属性名称对应一个属性值)。名称用来标识属性的语法和语义,并提供一个地址,通过该地址可以引用其语法和语义。
属性有两类——“活的(实时属性)”和“死的(静态属性)”:
活属性的语法和语义由服务器执行计算得出。一般包括以下情况:
- 属性的值由服务器保护和维护
- 属性的值由客户端维护,但服务器对提交的值执行语法检查。给定活动属性的所有实例都必须符合与该属性名关联的定义。
死属性的语法和语义由客户端负责维护,服务器仅仅逐字记录属性的值。
# 4.2 属性和HTTP Headers
直觉上以为,属性已经存在于HTTP Headers中。然而,在分布式创作环境中,会需要有一大堆的相关属性来描述资源的状态,通过HTTP Headers来设置/返回全部属性是低效的。因此,需要一种机制允许主体来识别其感兴趣的一组属性,并且仅设置或检索这些属性。
# 4.3 属性的值
属性的值总是一个(格式良好的)XML片段。
之所以选择XML,是因为它是一种灵活的、自描述的结构化数据格式,支持丰富的模式定义,还因为它支持多个字符集。XML的自描述特性允许通过添加元素来扩展任何属性。客户端在遇到扩展时不会崩溃,因为他们仍然拥有在原始模式中指定的数据,并且必须忽略他们不理解的元素。
XML对多字符集的支持允许将任何人类可读的属性值编码到用户熟悉的字符集中然后被读取。XML使用"XML:lang"属性支持多种语言,还可以处理多种语言使用相同字符集的情况。请注意,xml:lang作用域是递归的,子元素会应用父元素的xml:lang属性,除非它已被更局部作用域的属性覆盖。注意,一个属性只有一个值,它不会因语言环境而不同。
属性总是用一个包含了该属性名的XML元素来表示,被称为“属性名元素”。最简单的例子是空属性,它不同于不存在的属性:
<R:title xmlns:R="http://www.example.com/ns/"></R:title>
属性的值出现在以property name为节点名称的元素开关标签之间。值可以是任何组织良好格式的XML内容,包括纯文本内容和混合内容。服务器在存储和传输死属性时必须保留以下XML信息项(使用[REC-XML-INFOSET])中的术语):
- 对于属性名元素类型的信息项本身
- 命名空间名称[namespace name]
- 本地名称[local name]
- 以“xml:lang”或者其它类似方式命名的属性
- 类型元素或字符的子内容
- 对于属性值中的全部节点信息项
- 名称空间名称
- 本地名称
- 属性
- 类型元素或字符的字内容
- 对于属性值中的属性信息项
- 名称空间名称
- 本地名称
- 归一化值
- 对于属性值中的字符信息项
- 字符代码
- 由于一些XML词汇表中使用了前缀(例如XPath和XML Schema),服务器对于值中的任何信息项,应该予以保留前缀
- 前缀
上面没有列出的XML Infoset属性也可以由服务器保存,但是客户端绝对不能依赖于它们会被保存。除非另有定义,否则上述规则在默认情况下也将应用于活属性。
服务器必须忽略"XML:space"属性(如果存在的话),并且不使用它来更改空格处理方法。属性值中的空格是必要的。
# 4.3.1 举例 - 带有混合内容的属性
假设客户端像下面这样创建了一个名为 'author' 的死属性:
<D:prop xml:lang="en" xmlns:D="DAV:">
<x:author xmlns:x='http://example.com/ns'>
<x:name>Jane Doe</x:name>
<!-- Jane's contact info -->
<x:uri type='email' added='2005-11-26'>mailto:jane.doe@example.com</x:uri>
<x:uri type='web' added='2005-11-27'>http://www.example.com</x:uri>
<x:notes xmlns:h='http://www.w3.org/1999/xhtml'>
Jane has been working way <h:em>too</h:em> long on the long-awaited revision of <![CDATA[<RFC2518>]]>.
</x:notes>
</x:author>
</D:prop>
2
3
4
5
6
7
8
9
10
11
当这个属性被请求时,服务器将返回
<D:prop xmlns:D='DAV:'>
<author xml:lang='en' xmlns:x='http://example.com/ns' xmlns='http://example.com/ns' xmlns:h='http://www.w3.org/1999/xhtml'>
<x:name>Jane Doe</x:name>
<x:uri added="2005-11-26" type="email">mailto:jane.doe@example.com</x:uri>
<x:uri added="2005-11-27" type="web">http://www.example.com</x:uri>
<x:notes>
Jane has been working way <h:em>too</h:em> long on the long-awaited revision of <RFC2518>.
</x:notes>
</author>
</D:prop>
2
3
4
5
6
7
8
9
10
在这个例子中需要注意:
- 属性名本身的[前缀]没有被保留,因为它不重要,而其他所有[前缀]值都被保留,
- 属性值用双引号而不是单引号来重写(引号样式不重要),并且属性的顺序没有被保留,
- 属性名称元素本身返回了xml:lang属性(在请求中它被作为scope的属性进行设置,但是在响应中并不认为它的确切位置很重要,只要它被包含在scope之中就行),
- 标签之间的空白被保留(属性之间的空白没有),
- CDATA封装被替换为字符转义(反过来也是合法的),
- 注释项被剥离(就像处理指令项一样)。
实现时需注意:有些情况下,比如编辑场景,客户端可能要求XML内容被逐字符进行保存(比如属性排序或引用样式)。在这种情况下,客户机应该考虑通过使用纯文本属性值来存储转义后的所有字符。
# 4.4 属性名
属性名是一个全局唯一的标识符,它与提供了其相关语法和语义信息的模式相关联。
因为每一个属性的名字都是全局唯一的,客户可以为不用担心跨多资源的属性行为的一致性问题,在相同和不同服务器,只要属性还“活”着,这个属性的实现总会忠实于它的定义。
XML命名空间机制基于uri([RFC3986]),被用来给属性命名,因为它可以防止名称空间冲突,并提供不同程度的管理控制。
属性命名空间是平面的,也就是说,不需要去明确识别属性的层级结构。因此,如果一个资源上存在一个属性A和一个属性A/B,将不会去试图识别这两个属性之间的任何关系。预计最终将会产生一个单独的规范来解决与属性的层次等级相关的问题。
最后,你无法在单个资源上定义相同的属性两次,因为这将导致资源的属性命名空间冲突。
# 4.5 原始资源和输出资源
有些HTTP资源是由服务器动态生成的。对于这些资源,必然在某个地方存在控制资源如何生成的源内容。原始资源文件与输出HTTP资源的关系可以是一对一、一对一、多对一或多对多。HTTP中没有检查资源是否动态生成的机制,更不用说它的原始文件存在于何处或如何处理它们了。尽管这个问题终将会被会很有用的解决掉,但是很多并未解决这一问题的交互型WebDAV已经被广泛部署,而它们通常只处理静态资源。因此,原始资源与输出资源不一致的问题并没有在这个规范中得到解决,而将被推迟到一个单独的文档中。