我想通过一个丑陋的黑客来解决这个问题:向我的"任何XML"声明一个"假DTD"......举个例子解释:
输入(任何 XML 片段(
<root id="root">
<p id="p1"><i>Title</i></p>
<p id="p2"><b id="b1">AAA<sup>1</sup>, BBB<sup>2</sup></b></p>
</root>
PHP代码,
$DTD = '
<!DOCTYPE noname [
<!ATTLIST ANY
id ID #IMPLIED
>
]>';
$dom = new DomDocument();
$dom->loadXML( "$DTD'n$input" );
$e = $dom->getElementById('p1');
var_dump($e);
这段代码不是解决方案:$e是空的,我不明白为什么......那么,问题来了:是否有可能表达解决这个问题的"最小DTD"?
如果您只想使 ID 机制正常工作,最简单的选择是使用 xml:id
:
<root xml:id="root">
<p xml:id="p1"><i>Title</i></p>
<p xml:id="p2"><b xml:id="b1">AAA<sup>1</sup>, BBB<sup>2</sup></b></p>
</root>
根据 https://fosswiki.liip.ch/display/BLOG/GetElementById+Pitfalls 的说法,xml:id
应该在PHP中使用getElementById
。
您的尝试问题:
<!DOCTYPE
后面的元素名称必须与 XML 文档的根元素的名称匹配。在您的情况下,noname
!=root
,这不起作用。请参阅 http://www.w3.org/TR/xml/#sec-prolog-dtd。必须为每个元素声明属性。不能声明
ANY
的属性。即使元素的内容模型是ANY
的,你仍然必须声明所有可能发生的元素。
因此,无法仅为 ID 解析创建 DTD。以下内容进行验证,并且它实际上不能小于此值:
<!DOCTYPE root [
<!ELEMENT root (p+)>
<!ATTLIST root
id ID #IMPLIED>
<!ELEMENT p ANY>
<!ATTLIST p
id ID #IMPLIED>
<!ELEMENT b ANY>
<!ATTLIST b
id ID #IMPLIED>
<!ELEMENT sup (#PCDATA)>
<!ELEMENT i (#PCDATA)>
]>
<root id="root">
<p id="p1"><i>Title</i></p>
<p id="p2"><b id="b1">AAA<sup>1</sup>, BBB<sup>2</sup></b></p>
</root>
只要 XML 分析器不尝试验证,就可以提供较小的 DTD。此文档在非验证模式下被 xmllint(和 PHP(接受:
<!DOCTYPE anyname [
<!ATTLIST p id ID #IMPLIED>
]>
<root id="root">
<p id="p1"><i>Title</i></p>
<p id="p2"><b id="b1">AAA<sup>1</sup>, BBB<sup id="b1">2</sup></b></p>
</root>
并报告p
元素上的 ID 唯一性违规。
如果使用 --postvalid
选项运行 xmllint(或者在启用 LIBXML_DTDVALID
的情况下运行 PHP(,则会发出以下命令:
test.xml:4: element root: validity error : root and DTD name do not match 'root' and 'anyname'