当我尝试使用 DOMDocument 将 UTF-8 字符串写入 XML 文件时,它实际上写入的是字符串的十六进制表示法,而不是字符串本身。
例如:
ירושלים
代替:
ירושלים
任何想法如何解决这个问题?
当我尝试使用 DOMDocument 将 UTF-8 字符串写入 XML 文件时,它实际上写入的是字符串的十六进制表示法,而不是字符串本身。
例如:
ירושלים
代替:
ירושלים
任何想法如何解决这个问题?
好的,给你:
$dom = new DOMDocument('1.0', 'utf-8');
$dom->appendChild($dom->createElement('root'));
$dom->documentElement->appendChild(new DOMText('ירושלים'));
echo $dom->saveXml();
可以正常工作,因为在这种情况下,您构建的文档将保留指定为第二个参数的编码:
<?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>
因此,如果您 loadXML 某些东西,请确保它是
$dom = new DOMDocument();
$dom->loadXml('<?xml version="1.0" encoding="utf-8"?><root/>');
$dom->documentElement->appendChild(new DOMText('ירושלים'));
echo $dom->saveXml();
它会按预期工作。
作为替代方案,您还可以在加载文档后指定编码。
如果要使用 DOMDocument 输出 UTF-8,则需要指定。很简单,不是吗?如果你已经闻到了一个棘手的问题,那么你离得并不远,但乍一看,它确实是直截了当的。
考虑以下输出十六进制实体的(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 只包含完全有效的十六进制实体 - 即使在 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>
好的,都清楚了吗?所以这里有一个肮脏的小秘密:不管你有没有这些 XML 实体——对于文档来说它没有任何区别,它只是编写相同 XML 字符数据的不同形式。而且您已经感到被邀请了:让我们尝试CDATA作为第一个示例:
$dom = new DOMDocument();
$dom->loadXML("<root><![CDATA[ירושלים]]></root>");
$dom->save('php://output');
输出:
<?xml version="1.0"?>
<root><![CDATA[ירושלים]]></root>
就像之前的 XML 注释示例一样,这里没有使用 XML 实体。好吧,它们无论如何都是无效的,就像 XML-comment 示例一样。
对于概述,让我们创建一个包含所有这些的示例:
$dom = new DOMDocument();
$dom->loadXML("<!-- ירושלים --><root>ירושלים <![CDATA[ירושלים]]></root>");
$dom->save('php://output');
输出:
<?xml version="1.0"?>
<!-- ירושלים -->
<root>ירושלים <![CDATA[ירושלים]]></root>
得到教训:
提示:如果您的字符串具有与字符串编码不匹配的 XML 声明,或者您想在将字符串加载到DOMDocument之前更改两者中的任何一个,则需要更改 XML 声明和/或重新编码字符串。这已在对PHP XMLReader问题的回答中进行了介绍,通过展示类的工作方式来获取版本和编码。
XMLRecoder
希望就是这样。
[1]可能如果您从 HTTP 请求加载并提供流上下文并通过元数据标记字符编码 - 但这应该首先测试,我不知道。BOM 不起作用在某种程度上表明所有这些事情都不起作用。
显然将 documentElement 作为 $node 传递给 saveXML 可以解决这个问题,尽管我不能说我明白为什么。
例如
$dom->saveXML($dom->documentElement);
而不是:
$dom->saveXML();
来源:http ://www.php.net/manual/en/domdocument.savexml.php#88525
直截了当的回答是:
当你的函数开始时,在你得到内容之后,这样做:
$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);
然后做任何你打算用你的代码做的事情。
当我创建用于编写的 DOMDocument 时,我添加了以下参数:
dom = new DOMDocument('1.0','utf-8');
这些参数导致 UTF-8 字符串按原样写入。
$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