我想通过一个丑陋的黑客solve this problem:向我的“任何XML”声明一个“假DTD”......用一个例子解释:
INPUT(任何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是NULL,我不明白为什么......所以,问题:可以表达解决这个问题的“最小DTD”吗? < / p>
答案 0 :(得分:1)
如果您只想使用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'