12. 元素与属性的选择
注意: 关于何时使用属性、何时使用元素,没有硬性规定。 以下是设计者应考虑的一些事项;不给出理由说明。
12.1. 一般要点
-
属性比元素有更多限制,而所有设计都有一些元素,因此全元素设计是最简单的——但最简单不等于最好。
\
-
在树形数据模型中,元素通常在内部表示为节点,比用于表示属性的字符串消耗更多内存。 有时节点属于不同的应用特定类,在许多语言中表示这些类也需要占用内存。
\
-
在流式处理时,元素是逐个处理的(甚至可能是逐块处理,取决于你使用的 XML 解析器),而元素的所有属性及其值是一次性报告的,这会消耗内存,特别是当某些属性值很长时。
\
-
元素内容和属性值都需要适当转义,因此转义不应成为设计中的考虑因素。
\
-
在某些编程语言和库中,处理元素更容易;在另一些中,处理属性更容易。 警惕将处理的便利性作为标准。 特别是 XSLT 可以同等轻松地处理两者。
\
-
如果一条数据通常应该展示给用户,考虑使用元素;如果不需要,考虑使用属性。 (此规则经常因各种原因被违反。)
\
-
如果你正在扩展现有模式,按照该模式中的惯例来做。
\
-
合理的模式语言,即 RELAX NG 和 Schematron,对元素和属性的处理是对称的。 较老且较粗糙的模式语言 ,如 DTD 和 XML Schema,往往对元素有更好的支持。
12.2 使用元素
-
如果某些数据在数据模型中可能出现多次,使用元素而不是引入名为 foo1, foo2, foo3 … 的属性。
\
-
使用元素来表示可以被视为独立对象的信息,以及通过父子关系与另一条信息相关联的信息。
\
-
当数据包含严格的类型化或关系规则时,使用元素。
\
-
如果两条数据之间的顺序很重要,对它们使用元素:属性本质上是无序的。
\
-
如果一条数据有或可能有其自身的子结构,将它放在元素中:将子结构放入属性总是很混乱的。 类似地,如果数据是某个更大数据的组成部分,将其放在元素中。
\
-
上一条规则的例外:多个以空白分隔的标记可以安全地放在属性中。 原则上,分隔符可以是任何字符,但模式语言验证器目前只能处理空白,因此最好坚持使用空白。
\
-
如果一条数据跨越多行,使用元素:XML 解析器会将属性值中的换行符转换为空格。
\ -
如果一条数据非常大,使用元素以便其内容可以流式传输。
\ -
如果一条数据使用自然语言,将其放在元素中,这样你可以使用 xml:lang 属性来标记所使用的语言。 某些类型的自然语言文本,如日语,经常使用通常以子元素表示的注音标注(annotations) ;希伯来语和阿拉伯语等从右到左的语言可能同样需要子元素来正确管理双向性(bidirectionality) 。
12.3 使用属性
-
如果数据是来自枚举、代码列表或受控词汇表的代码,尽可能将其放在属性中。 例如,语言标签、货币代码、医疗诊断代码等最好作为属性处理。
\
-
如果一条数据确实是另一条数据的元数据(例如,表示主数据所服务的类或角色,或指定处理它的方法),尽可能将其放在属性中。
\
-
特别是,如果一条数据是另一条数据的 ID,或者是对此类 ID 的引用,将标识数据放在属性中。 当它是 ID 时,使用 xml:id 作为属性名称。
\
-
超文本引用按惯例放在 href 属性中。
\
-
如果一条数据适用于某个元素及其所有后代元素(除非在某些后代元素中被覆盖),按惯例将其放在属性中。 知名的例子有 xml:lang、xml:space、xml:base 和命名空间声明。
\
-
如果简洁性确实是最重要的,使用属性,但也可以考虑使用 gzip 压缩代替——它对具有高度重复结构的文档效果非常好。
\
\