ID解析有一个最小的DTD?

时间:2013-09-30 23:59:38

标签: php xml domdocument dtd

我想通过一个丑陋的黑客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>

1 个答案:

答案 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+Pitfallsxml:id应与PHP中的getElementById一起使用。


您尝试的问题:

  1. <!DOCTYPE后面的元素名称必须与XML文档的根元素名称匹配。在您的情况下,noname!= root,这不起作用。请参阅http://www.w3.org/TR/xml/#sec-prolog-dtd

  2. 必须为每个元素声明属性。您无法声明ANY的属性。即使元素的内容模型是ANY,您仍然必须声明可能出现的所有元素。

  3. 因此无法仅为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'