Skip to content

DTD 元素 vs 属性

在设计 XML 文档的结构时(结构可以形式化(formalized)为 DTD 或 Schema),你需要决定是使用子元素还是属性来表示信息片段。

如前所述,没有严格的 XML 语法规则来规定这种选择,但 DTD/Schema 设计原则和最佳实践提供了指导。

让我们回顾 person 示例:

用于 gender 的属性:

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

用于 gender 的元素:

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

两者都是有效的 XML 并传达相同的信息。选择会影响结构、验证能力(尤其是在使用 XSD 时)和处理的便利性。

这些指南有助于做出一致且合乎逻辑的选择:

  • 元素用于:
    • 核心数据内容。
    • 可能包含结构的信息(例如,地址、日期组成部分)。
    • 可以出现多次的信息(例如,电话号码、电子邮件地址)。
    • 未来可能需要扩展更多细节的数据。
    • 当一个元素关联的信息片段过多时,用于提高可读性。

属性用于:

    • 元数据(关于数据的信息,例如,xml:id、unit、language、status)。
    • 不需要结构的简单、原子值。
    • 控制处理或呈现(例如,type、role)。

再次考虑日期示例:

属性(推荐 ISO 8601 格式):

<note date="2024-07-01">
...
</note>

结构化元素(通常因灵活性而优先选择):

<note>
<date>
<year>2024</year>
<month>07</month>
<day>01</day>
</date>
...
</note>

结构化元素的方法使得单独查询或处理年、月或日变得更容易。

你的选择会影响你在 DTD 或 Schema 中定义结构的方式:

  • DTD 中的属性: 使用 <!ATTLIST ...> 声明定义,指定属性名称、类型(例如,CDATA、ID、IDREF、枚举类型)以及默认值/要求(#REQUIRED(必需)、#IMPLIED(可选))。
  • DTD 中的元素: 使用 <!ELEMENT ...> 声明定义,指定元素名称及其允许的内容模型(content model)(例如,其他元素、#PCDATA、EMPTY)。
  • XML Schema (XSD): 为元素和属性提供了更丰富的功能,包括精确的数据类型(整型、日期型、布尔型、模式匹配)、出现约束(occurrence constraint)(最小/最大出现次数)以及更复杂的结构。在元素/属性之间的选择在使用 XSD 时可能具有更重要的验证影响。

虽然 DTD 有其局限性(例如,属性的基本类型检查、不支持命名空间),但这个基本决定会影响你如何声明你预期的结构。

避免给元素添加过多的属性,因为它会损害可读性和可维护性:

可读性较差的示例:

<note to="Tove" from="Jani" date="2024-07-01" priority="high" status="unread" ... />

像 priority 或 status 这样的元数据可能适合作为属性,但像 to、from、date 这样的核心内容通常更适合作为元素。

如之前强调的,使用属性作为唯一标识符是一种标准且推荐的做法。为此目的使用 xml:id 属性。

<messages xmlns:xml="http://www.w3.org/XML/1998/namespace">
<note xml:id="p501">
<to>Tove</to>
...
</note>
<note xml:id="p502">
<to>Jani</to>
...
</note>
</messages>

xml:id 属性明确指定了一个用于引用元素的唯一标识符,符合元数据的定义。

总之,优先使用元素表示内容和结构,而将属性用于元数据、标识符和简单配置标志。