由于换行导致的 DTD 字符数据验证错误

DTD character data validation error due to linebreak

我有以下 fake.dtd 文件:

<!ELEMENT outer - - (#PCDATA, foo, bar) >
<!ELEMENT foo - o (#PCDATA) >
<!ELEMENT bar - - (#PCDATA) >

以及以下 SGML 文档:

<!DOCTYPE outer SYSTEM "fake.dtd">
<OUTER>Document Title
    <FOO>1234
    <BAR>wxyz</BAR>
</OUTER>

我在使用 nsgmls:

时收到验证错误

4:19:E: character data is not allowed here

注意把</OUTER></BAR>放在同一行就解决了问题;错误是指换行符。

有没有办法让 SGML 保持原样(因为我已经有数千个这样的文档),但更改 DTD 以使其有效?

outer 元素的末尾添加另一个 #PCDATA 似乎很愚蠢,因为这会使换行符以外的字符合法。

看似无害的空格实际上是重要的字符数据,这会导致错误。这有时称为 "pernicious mixed content"。您已经暗示了一个解决方案(允许 #PCDATAbar 元素之后):

<!ELEMENT outer - - (#PCDATA, foo, bar, #PCDATA) >

另一种选择是允许 #PCDATA 和任何顺序的元素(这是必须在 XML 中声明混合内容的方式):

<!ELEMENT outer - - (#PCDATA|foo|bar)* >

我想不出别的了。无法将 #PCDATA 内容限制为仅某些字符。

SGML 标准 (ISO 8879:1986/A1:1988, 11.2.4) 明确建议不要使用 内容模型,如 (#PCDATA, foo, bar)(强调我的):

NOTE - It is recommended that “#PCDATA” be used only when data characters are to be permitted anywhere in the content of the element; that is, in a content model where it is the sole token, or where or is the only connector used in any model group.

尽管提及 #PCDATA 仅作为组中的第一个标记,您的 outer 元素类型仍被声明为具有 混合内容 ,因此数据字符可以出现在任何地方:这就是为什么 </BAR> 之后的换行符(又名 "record end")被识别为 数据字符 一方面不仅仅是 分隔符 ,但另一方面没有相应的 #PCDATA 标记来吸收它,因此出现错误。 (只有省略的 </FOO> 结束标记避免了之前行中的相同错误!)


在这种情况下,正确且常见的方法是将 "Document Title" 放入实际的 title 元素中——为此可以允许省略 both 开始和结束标签:

<!ELEMENT outer - - (title, foo, bar) >
<!ELEMENT title o o (#PCDATA) >

现在

  • 您的文档实例未经修改即有效,
  • outer 内容模型仍然反映了元素的正确顺序,
  • outer元素有元素内容不再混合内容),
  • 并且 "Document Title" 文本最终出现在它自己的 title 元素中,这是应该的。

(在多个标准 DTD 中使用了相同的技术,例如标准附件 E 中的 "General Document" 示例。)