XML 元素与属性的区别

在 XML 中,关于何时使用属性、何时使用子元素并没有硬性规定。

元素与属性的使用

数据既可以存储在子元素中,也可以存储在属性内。

请看以下示例:

<person sex="female">
  <firstname>Anna</firstname>
  <lastname>Smith</lastname>
</person>

<person>
  <sex>female</sex>
  <firstname>Anna</firstname>
  <lastname>Smith</lastname>
</person>

第一个例子中将性别存储为属性,第二个例子中则作为子元素。两个示例传递的信息完全一致。

关于属性与子元素的使用时机并无明文规定。根据经验,属性在 HTML 中颇为便捷,但在 XML 中应尽量避免使用。若信息具备数据特性,建议优先采用子元素。

我的首选方案

我更倾向于使用子元素存储数据。

以下三个 XML 文档包含完全相同的信:

第一个例子使用日期属性:

<note date="12/11/2007">
  <to>George</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>

第二个例子使用日期元素:

<note>
  <date>12/11/2007</date>
  <to>George</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>

第三个例子使用扩展日期元素(这是我最推崇的方式):

<note>
  <date>
    <day>12</day>
    <month>11</month>
    <year>2007</year>
  </date>
  <to>George</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>

是否应该避免使用属性?

属性存在诸多局限性:

  • 无法存储多值数据(子元素可以)
  • 不易扩展(难以适应未来变更)
  • 不能描述数据结构(子元素可以)
  • 程序代码处理起来更为复杂
  • 针对 DTD 进行值校验较为困难

若将属性作为数据容器,会导致文档难以阅读和维护。建议使用元素描述数据,属性仅应用于存储与数据内容无关的辅助信息。

切忌采用这种不符合 XML 设计理念的写法:

<note day="12" month="11" year="2007"
to="George" from="John" heading="Reminder"
body="Don't forget the meeting!">
</note>

属性规则的例外情况

规则总有例外。

在以下场景中我们会破例使用属性:

当需要为元素分配 ID 引用时。这些 ID 引用可用于访问 XML 元素,其作用类似于 HTML 中的 name 或 id 属性。

具体示例如下:

<messages>
<note id="p501">
  <to>George</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>

<note id="p502">
  <to>Jani</to>
  <from>Tove</from>
  <heading>Re: Reminder</heading>
  <body>I will not!</body>
</note>
</messages>

这些示例中的 ID 仅是用于区分不同笔记的计数器或唯一标识符,并不属于笔记数据本身。

简而言之,元数据(描述数据的数据)适合存储为属性,而数据本身应当存储为元素。