DOMDocument解析CDATA中的数据

时间:2015-04-20 19:42:02

标签: php xml dom

我有这个xml(必须通过HTML剪切/粘贴)。

<tr>
    <td>http://www.example.co.uk/the-view-from-22/feed/</td>
    <td>Example Blogs » The View from 22 » Example Blogs</td>
    <td>http://blogs.example.co.uk/</td>
    <td><![CDATA[Listen: The Example&rsquo;s verdict on the debate]]></td>
    <td>http://blogs.example.co.uk/coffeehouse/2015/04/podcast-special-the-debate/</td>
</tr>

它正被加载到XML dom文档

   $dom = new DOMDocument();
   $dom->preserveWhiteSpace = false;
   $dom->formatOutput = true;
   $dom->loadXML( $xml->asXML() );
   return $dom->saveXML();

但这引发了关于&amp; rsquo的错误;实体没有被定义。

  

警告:DOMDocument :: loadXML()[domdocument.loadxml]:实体'rsquo'未在实体中定义,...

正如在CDATA部分中一样,我期望DOMDocument将其视为文本而忽略它......但它没有......有没有解决方法呢?

数据被直接从视图中的mysql数据库中提取出来,因此首先“修复”的空间不大 - 我在视图的select子句中添加了CDATA,这是我尝试的修复!

修改 根据以下建议追踪它(干杯!)

使用$ xml-&gt; addChild($ key,$ value)加载数据,但$ value的格式正如您推测的那样编码。

所以我只想尝试一下......

How to write CDATA using SimpleXmlElement?

它的确有效 - 我现在正在加载orignal doc: -

 if (strpos(strtoupper($value),'<![CDATA[') === 0 && strpos(strrev($value),'>]]') === 0) {
                $child = $xml->addChild( $key );
                $node = dom_import_simplexml($child);
                $no   = $node->ownerDocument;
                $node->appendChild($no->createCDATASection(substr($value,9,strlen($value)-12)));

                //simple key/value child pair
            } else {
                $xml->addChild( $key, $value );
            }

2 个答案:

答案 0 :(得分:0)

如果它只有一个&rsquo;而不是大量的特殊字符,你可以尝试替换它。

 $dom = new DOMDocument();
 $dom->preserveWhiteSpace = false;
 $dom->formatOutput = true;
 $xml = $xml->asXML();

 $xml = str_replace('&rsquo;', '&#8217;', $xml);

 $dom->loadXML($xml);
 return $dom->saveXML();

真正的问题是,&rsquo;是如何进入您的数据库的。 在插入之前修复它...然后你可以拉出格式良好的XML。 https://stackoverflow.com/a/3142636/1163786

或使rsquo成为有效的实体:

<!DOCTYPE ROOT_XML_ELEMENT [ <!ENTITY rsquo "&#8217;"> ]>

如果您的内容是UTF-8,只需将其替换为:


(我认为)最初的问题就是这个问题:

警告:实体'rsquo'未在实体中定义,行:...

<?php

$xml = <<<XML
<tr>
    <td>Listen: The Example&rsquo;s verdict on the debate></td>
</tr>
XML;

$doc = new DOMDocument();
$doc->presverWhitespace = false;
$doc->formatOutput = true;
$doc->loadXML($xml);
echo $doc->saveXML();

因为实体'rsquo'不是有效的XML,所以会弹出错误。现在,pperrin通过添加“CDATA修复”解决了这个问题。这就是我理解这个问题的方式。

您不需要CDATA - 如果您

  • 在根目录或
  • 定义实体
  • 将其添加到DTD以使其有效或
  • 手动更换(见上文)
  • 或只是在进入数据库之前修复

答案 1 :(得分:0)

正如我用my example code所证明的那样,我无法重现你的问题。因此,我得出的结论是,您必须具有双重编码,并且双重编码数据是XML解析器扼流的地方,并且正确地为您提供警告。只是由于双重编码,这并不是立即可见的。

对数据进行一次解码,以便对其进行正确的XML编码。然后DOMDocument可以轻松加载它。


旧答案(对于通过搜索引擎来到这里的用户仍然有用):

我怀疑您的问题是$xml->asXML(),因为CDATA部分不会产生该错误。

首先有一种更好的方法可以转换为DOMDocument:

$dom = dom_import_simplexml($xml)->documentElement;

这也应该保留CDATA部分的编码(不是100%肯定)。对于您的格式化,您可能需要重新加载文档,但也许您不需要。尝试

$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$result = $dom->saveXML();

如果结果还不是您想要的预期漂亮打印格式, 你可以从dom重新加载文件:

$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($dom->saveXML());
$result = $dom->saveXML();

我希望因为这是DOMDocument,所以以前的CDATA编码字符与实体类似没有问题。

转换函数dom_import_simplexml() is in the manual以及SimpleXML和DOM共享公共虚拟接口,如果要在DOM和SimpleXML之间切换,反之亦然,使用它应该是首选方式。