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>ירושלים</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>ירושלים</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>ירושלים <![CDATA[ירושלים]]></root>"); $dom->save('php://output');
输出:
<?xml version="1.0"?> <!-- ירושלים --> <root>ירושלים <![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);
然后做任何你打算做你的代码。