当用于属性的声明值时,CDATA 指的是属性的实际值(字符数据),而不是解析它的上下文。另一方面,在解析元素时,我们需要区分不带标记的字符数据 (CDATA) 和预期分隔符的已解析字符数据 (PCDATA)。
乍一看,这似乎是任意的,但事实并非如此(参见此处和此处)。
在 SGML 中,属性值规范可以被引用(属性值文字)或不被引用(属性值)。
attribute value specification = attribute value literal | attribute value
当属性不加引号时,只允许使用 NAME 字符,并且对于某些声明的值(例如 NUMBER)可能会进一步限制。
另一方面,属性值 literal的内容是由 LIT/LITA 分隔符(在参考具体语法中分别为双引号和单引号)包围的可替换字符数据序列。
attribute value literal =
( LIT , replaceable character data *, LIT) |
( LITA , replaceable character data *, LITA)
可替换字符数据“与 CDATA 类似,但实体引用和字符引用被识别”(Goldfarb,SGML 手册)。
因此,属性值文字中实体引用的替换不依赖于属性的声明值。因此,如果您拥有<!ENTITY foo "bar">
并且<elem attr="&foo;">
实体引用&foo;
将在可替换字符数据的上下文中进行解析(LIT 识别模式),则产生<elem attr=bar>
. 是否attr
声明为 CDATA、NAME 或其他都没有关系。
更新
不必说必须解析属性中的实体,因为所有属性类型都有相同的解析规则:如果属性值以引号 (LIT) 开头,则实体被识别(可替换字符数据)并且值当找到匹配的结束引号时结束。
这里的 CDATA 意味着一个有效的属性必须包含扩展实体后的任意字符数据。如果该属性被声明为 NUMBER,则需要包含数字字符(或扩展为数字字符的实体)。
在上面的示例中,具有值的 CDATA 属性"&foo;"
等价于"bar"
,与具有值的 NUMBER 属性"0"
等价于的方式相同"0"
(即使序列 "0"
包含数字以外的字符)。