php:当我试图写UTF-8的时候,使用DomDocument来写它的hex符号

当我尝试使用DomDocument将UTF-8string写入XML文件时,它实际上会写入string的hex表示法而不是string本身。

例如:

ירושלים

而不是:ירושלים

任何想法如何解决这个问题?

好的,在这里你去:

 $dom = new DOMDocument('1.0', 'utf-8'); $dom->appendChild($dom->createElement('root')); $dom->documentElement->appendChild(new DOMText('ירושלים')); echo $dom->saveXml(); 

将正常工作,因为在这种情况下,您构build的文档将保留指定为第二个参数的编码:

 <?xml version="1.0" encoding="utf-8"?> <root>ירושלים</root> 

但是,一旦将XML加载到不指定编码的Document中,您将失去在构造函数中声明的任何内容,这意味着:

 $dom = new DOMDocument('1.0', 'utf-8'); $dom->loadXml('<root/>'); // missing prolog $dom->documentElement->appendChild(new DOMText('ירושלים')); echo $dom->saveXml(); 

将不会有utf-8的编码:

 <?xml version="1.0"?> <root>&#x5D9;&#x5E8;&#x5D5;&#x5E9;&#x5DC;&#x5D9;&#x5DD;</root> 

所以,如果你加载XML的东西,确保它

 $dom = new DOMDocument(); $dom->loadXml('<?xml version="1.0" encoding="utf-8"?><root/>'); $dom->documentElement->appendChild(new DOMText('ירושלים')); echo $dom->saveXml(); 

它会按预期工作。

另外,您也可以在加载文档后指定编码 。

如果你想用DOMDocument输出UTF-8,你需要指定。 简单,不是吗? 如果你已经嗅到了一个诡计的问题,那么你不是太遥远,但是一见钟情,它确实很简单。

考虑输出hex实体的以下(UTF-8编码)代码示例:

 $dom = new DOMDocument(); $dom->loadXml('<root>ירושלים</root>'); $dom->save('php://output'); 

输出:

 <?xml version="1.0"?> <root>&#x5D9;&#x5E8;&#x5D5;&#x5E9;&#x5DC;&#x5D9;&#x5DD;</root> 

正如所写的,如果你想输出这个为UTF-8,你需要指定它,它是直截了当的:

 ... $dom->encoding = 'UTF-8'; $dom->save('php://output'); 

然后输出显式为UTF-8:

 <?xml version="1.0" encoding="UTF-8"?> <root>ירושלים</root> 

非常简单的部分。 如果你对这些肮脏的小细节感兴趣,你可以自由阅读 – 如果不是,请不要问“为什么? :)。

我只是写了“以UTF-8 显式 ”,因为在第一个例子中,输出是UTF-8编码,XML只包含hex实体,即使在UTF-8中也是如此。

你已经注意到,我从这里开始挑选,但记住: UTF-8 XML的默认编码

如果你现在开始说:嘿,等等,如果默认编码是UTF-8,为什么PHP的DOMDocument首先使用实体?

事实上,这并不违背问题中的发现。 并不总是

请参阅下面的示例,该示例使用XML注释而不是包含Ivrit字母的节点值:

 $dom = new DOMDocument(); $dom->loadXml('<root><!-- ירושלים --></root>'); $dom->save('php://output'); 

输出:

 <?xml version="1.0"?> <root><!-- ירושלים --></root> 

好的,都清楚了? 所以这里这个肮脏的小秘密是:不pipe你是否有那些XML实体 – 对于文档来说它没有什么区别,它只是写入相同的XML字符数据的一种不同的forms。 你已经感受到了邀请:让我们尝试CDATA代替第一个例子:

 $dom = new DOMDocument(); $dom->loadXML("<root><![CDATA[ירושלים]]></root>"); $dom->save('php://output'); 

输出:

 <?xml version="1.0"?> <root><![CDATA[ירושלים]]></root> 

正如前面的XML-comment示例所示,这里没有使用XML实体。 那么,它们无论如何都不会有效,就像使用XML注释示例一样。

对于概述,可以创build一个包含所有这些的示例:

 $dom = new DOMDocument(); $dom->loadXML("<!-- ירושלים --><root>&#x5D9;רושלים <![CDATA[ירושלים]]></root>"); $dom->save('php://output'); 

输出:

 <?xml version="1.0"?> <!-- ירושלים --> <root>&#x5D9;&#x5E8;&#x5D5;&#x5E9;&#x5DC;&#x5D9;&#x5DD; <![CDATA[ירושלים]]></root> 

得到教训:

  • 总是使用UTF-8。 除非指定了UTF-8编码,否则只有一些实体用于PCDATA。 如果指定了与UTF-8编码不同的值,则应用不同的规则 。
  • 您不能指定是否要使用实体或通过在PHP DOMDocument中将XML文档加载为UTF-8编码的string来进行输出。 即使使用libxml标志也不提供BOM。 [1]
  • 您可以通过将文档编码设置为UTF-8来指定您不想使用实体。
  • 如果可以的话,你可以操纵inputstring,该inputstring有一个XML声明,指定文档编码,如gordon的答案中所述 。

提示:如果你的string有一个XML-Declaration与string编码不匹配,或者你想把string加载到DOMDocument 之前改变它们你需要改变XML-Declaration和/或重新编码string。 PHP XMLReader问题的答案已经涵盖了这个问题,通过显示XMLRecoder类的工作方式来获取版本和编码 。

这就是希望。


[1]也许如果你从一个HTTP请求加载,你提供stream上下文,并通过元数据标记字符编码 – 但这应该首先testing,我不知道。 物料清单不起作用有些迹象表明,所有这些都不起作用。

显然将documentElement作为$ node传递给saveXML可以解决这个问题,尽pipe我不能说我明白为什么。

例如

 $dom->saveXML($dom->documentElement); 

而不是:

 $dom->saveXML(); 

资料来源: http : //www.php.net/manual/en/domdocument.savexml.php#88525

当我创buildDomDocument写作时,我添加了以下参数:

 dom = new DOMDocument('1.0','utf-8'); 

这些参数导致UTF-8string按原样写入。

 $doc = new DOMDocument(); $doc->loadHTML('<?xml encoding="UTF-8">' . $html); // dirty fix foreach ($doc->childNodes as $item) if ($item->nodeType == XML_PI_NODE) $doc->removeChild($item); // remove hack $doc->encoding = 'UTF-8'; // insert proper 

要点答案是:

当你的function开始时,在获取内容之后,执行以下操作:

  $content = mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8'); 

然后启动新的文件等。检查这个例子:

  if ( empty( $content ) ) { return false; } $doc = new DOMDocument('1.0', 'utf-8'); libxml_use_internal_errors(true); $doc->LoadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); 

然后做任何你打算做你的代码。