在XML中使用文档类型声明

3

我正在使用一个单独的 .dtd 文件作为我的自定义 xml 文件的文档类型:

names.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE name SYSTEM "names.dtd">
<names>
    <name>
        <text>Pep&eacute;</text>
        <creator>&lost;</creator>
        <history>&lost;</history>
    </name>
    <name>
        <text>Charles</text>
        <creator>James</creator>
        <history>&lost;</history>
    </name>
</names>

names.dtd

<!ELEMENT name (text, creator+, history)>
<!ELEMENT text (#PCDATA)>
<!ELEMENT creator (#PCDATA)>
<!ELEMENT history (#PCDATA)>

<!-- Placeholder/unknown history or creator name -->
<!ENTITY lost "Lost in the depths of time.">
<!ENTITY eacute "é">

然而尝试访问names.xml时,我收到了以下错误:

XML解析错误:未定义的实体 位置: http://localhost/.../names.xml 第5行, 第18列:

<text>Pep&eacute;</text>
---------^

仅作澄清,names.xml和names.dtd在同一目录下,使用http://localhost/.../names.dtd也不起作用。

然而,在names.xml中将<!ENTITY放入<!DOCTYPE中似乎是可行的。有人能提供建议吗?

2个回答

2
火狐浏览器不加载外部DTD(Safari也是如此;看起来没有浏览器会这样做)。如果我告诉 xmllint 加载外部 DTD,您的 DTD 和 XML 就可以在其中正常工作。
$ xmllint --loaddtd names.xml 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE names SYSTEM "names.dtd">
<names>
    <name>
        <text>Pep&eacute;</text>
        <creator>&lost;</creator>
        <history>&lost;</history>
    </name>
    <name>
        <text>Charles</text>
        <creator>James</creator>
        <history>&lost;</history>
    </name>
</names>

编辑:正如hsivonen在评论中指出的那样,使用DTD解析外部实体是一个糟糕的想法。通常不应该在网页上使用DOCTYPE或DTD。如果您想验证文档,应该使用单独的模式(建议使用RELAX NG),而不是嵌入在文档本身中的DTD。

浏览器加载DTD是一个非常糟糕的想法:http://hsivonen.iki.fi/no-dtd/ - hsivonen
是的,你说得对。我在想他们是否甚至加载本地DTD。不过这是一个关于为什么DTD不是好主意的好参考。 - Brian Campbell
@hsivonen 我更新了我的回答,包括为什么 DTD 是一个坏主意的信息;感谢你提供的好文章。 - Brian Campbell

2

如果你想通过在Firefox中打开文档来确定DTD是否正确,请不要这样做。Firefox不会将XML和DTD通过正确的XML解析器传递。请在IE中打开您的XML文档,这将使您的文档通过MSXML解析器。

在IE中打开XML文档时,它会报告您的DTD使用了无效字符的错误。您需要使用eacute的字符代码而不是字符本身。以下是我用于解决问题的代码...

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE NAME SYSTEM "names.dtd">
<names>
    <name>
        <text>Pep&eacute;</text>
        <creator>&lost;</creator>
        <history>&lost;</history>
    </name>
    <name>
        <text>Charles</text>
        <creator>James</creator>
        <history>&lost;</history>
   </name>
</names>

并且。
<!ELEMENT name (text, creator+, history)>
<!ELEMENT text (#PCDATA)>
<!ELEMENT creator (#PCDATA)>
<!ELEMENT history (#PCDATA)>

<!ENTITY lost "Lost in the depths of time.">
<!ENTITY eacute "&#233;">

如果编码正确,您可以直接在外部DTD主题中使用“é”字符。默认情况下,它应该是UTF-8;您可以通过在.dtd顶部包含一个不同的“编码”的“文本声明”来更改它。(文本声明基本上与<?xml?>声明相同。) - bobince
顺便说一下,XML解析器不包含外部引用(如DTD外部子集)是合法的,浏览器不允许在网页上使用它是正确的,因为它可以启用跨站点脚本。在这种情况下,未声明的实体引用会发生什么取决于实现。 - bobince
更正:Firefox使用了一个适当的XML解析器,但实体解析器(将系统ID解析为字节流的东西)已被修改为将外部DTD解析为零长度流。 - hsivonen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接