在XML DTD中-定义元素时,我们使用#PCDATA表示该元素可以包含任何可解析的文本。在定义属性时,我们使用CDATA表示其值可以是任何字符数据。
XML中使用的CDATA是XML解析器无法解析的东西(多字符转义序列)。一贯地,当我们使用CDATA来定义属性时;解析器不应该解析它。但是,它确实解析了!
那么,为什么不能用PCDATA代替CDATA来定义属性呢?
更新-保持这种方式是为了与SGML向后兼容。SGML中这样命名的原因是什么?
在属性的声明值中使用时,CDATA指的是属性(字符数据)的实际值,而不是解析它的上下文。另一方面,在解析元素时,我们需要区分没有标记的字符数据(CDATA)和需要分隔符的已解析字符数据(PCDATA)。
乍一看,这似乎是武断的,但事实并非如此(请参阅此处和此处)。
在SGML中,属性值规范可以被引用(attribute value literal),也可以被取消引用(attribute-value 当属性不带引号时,只允许使用NAME字符,并且对于某些已声明的值(如NUMBER),这可能会受到进一步限制。 另一方面,属性值literal的内容是由LIT/LITA分隔符(在引用具体语法中分别为双引号和单引号)包围的可替换字符数据序列。 可替换字符数据"与CDATA类似,但实体引用和字符引用是可识别的"attribute value specification = attribute value literal | attribute value
attribute value literal =
( LIT , replaceable character data *, LIT) |
( LITA , replaceable character data *, LITA)
因此,属性值文字中实体引用的替换不取决于属性的声明值。因此,如果您有<!ENTITY foo "bar">
和<elem attr="&foo;">
,实体引用&foo;
将在可替换字符数据的上下文中解析(LIT识别模式),生成<elem attr=bar>
。attr
是否声明为CDATA、NAME或其他什么都无关紧要。
更新
没有必要说必须解析属性中的实体,因为所有属性类型都有相同的解析规则:如果属性值以引号(LIT)开头,则实体被识别(可替换字符数据),并且当找到匹配的结束引号时,值结束。
这里CDATA意味着在扩展实体之后,有效属性必须包含任意字符数据。如果属性被声明为NUMBER,那么它将被要求包含数字字符(或扩展为数字字符的实体)。
在上面的示例中,值为"&foo;"
的CDATA属性等效于"bar"
,就像值为"0"
的NUMBER属性等效于"0"
一样(即使序列"0"
包含数字以外的字符)。
CDATA部分与CDATA属性类型不同,就像您在元素中使用的那样。
您最有可能观察到的解析(如正在解析的实体引用)来自属性值规范化。