PCDATA vs CDATA in XML DTD



在XML DTD中-定义元素时,我们使用#PCDATA表示该元素可以包含任何可解析的文本。在定义属性时,我们使用CDATA表示其值可以是任何字符数据。

XML中使用的CDATA是XML解析器无法解析的东西(多字符转义序列)。一贯地,当我们使用CDATA来定义属性时;解析器不应该解析它。但是,它确实解析了!

那么,为什么不能用PCDATA代替CDATA来定义属性呢?

更新-保持这种方式是为了与SGML向后兼容。SGML中这样命名的原因是什么?

在属性的声明值中使用时,CDATA指的是属性(字符数据)的实际值,而不是解析它的上下文。另一方面,在解析元素时,我们需要区分没有标记的字符数据(CDATA)和需要分隔符的已解析字符数据(PCDATA)。

乍一看,这似乎是武断的,但事实并非如此(请参阅此处和此处)。

在SGML中,属性值规范可以被引用(attribute value literal),也可以被取消引用(attribute-value

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,那么它将被要求包含数字字符(或扩展为数字字符的实体)。

在上面的示例中,值为"&foo;"的CDATA属性等效于"bar",就像值为"&#48;"的NUMBER属性等效于"0"一样(即使序列"&#48;"包含数字以外的字符)。

CDATA部分与CDATA属性类型不同,就像您在元素中使用的那样。

您最有可能观察到的解析(如正在解析的实体引用)来自属性值规范化。

最新更新