内部 DTD 中的参数实体

Parameter entities in internal DTD

我有以下 simple.dtd:

<!ENTITY % placeholder "my, element, list">
<!ELEMENT root (%placeholder;)>
<!ELEMENT my (#PCDATA)>
<!ELEMENT element (#PCDATA)>
<!ELEMENT list (#PCDATA)>

simple.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE root SYSTEM "simple.dtd">

<root>
    <my />
    <element />
    <list />
</root>

这可行且有效。

但是完全相同的 DTD 内联:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE root [
        <!ENTITY % placeholder "my, element, list">
        <!ELEMENT root (%placeholder;)>
        <!ELEMENT my (#PCDATA)>
        <!ELEMENT element (#PCDATA)>
        <!ELEMENT list (#PCDATA)>
]>

<root>
    <my />
    <element />
    <list />
</root>

失败并出现错误:

$ xmllint --valid simple.xml
simple.xml:4: parser error : ContentDecl : Name or '(' expected
        <!ELEMENT root (%placeholder;)>
                        ^
simple.xml:4: parser error : expected '>'
        <!ELEMENT root (%placeholder;)>
                        ^
Entity: line 1: parser error : internal error: xmlParseInternalSubset: error detected in Markup declaration

 %placeholder; 
              ^
Entity: line 1: 
my, element, list
^
Entity: line 1: parser error : DOCTYPE improperly terminated
 %placeholder; 
              ^
Entity: line 1: 
my, element, list
^
Entity: line 1: parser error : Start tag expected, '<' not found
 %placeholder; 
              ^
Entity: line 1: 
my, element, list
^

为什么会这样?

在 DTD 的内部子集中,标记声明中不允许引用参数实体。您必须使用外部 DTD,即单独的文件。这在 XML 规范 here.

中记录为格式良好的约束

spec 状态:

In the internal DTD subset, parameter-entity references must not occur within markup declarations; they may occur where markup declarations can occur. (This does not apply to references that occur in external parameter entities or to the external subset.)

所以在内部子集中,您不能从标记声明中引用参数实体。

虽然您可以从与标记声明相同的级别引用它。

这意味着您必须 declare/reference 像这样的参数实体:

<!DOCTYPE root [
    <!ENTITY % placeholder "<!ELEMENT root (my, element, list)>">
    %placeholder;
    <!ELEMENT my (#PCDATA)>
    <!ELEMENT element (#PCDATA)>
    <!ELEMENT list (#PCDATA)>
]>
<root>
    <my />
    <element />
    <list />
</root>