我花了很长时间才发现
DOMDocument->formatOutput = true
只有在也设置了以下情况下,才会对从磁盘加载的文档产生影响
DOMDocument->preserveWhiteSpace = false ....
希望这能避免有人头疼。
(PHP 5, PHP 7, PHP 8)
DOMDocument::save — 将内部 XML 树转储回文件
从 DOM 表示创建 XML 文档。此函数通常在从头开始构建新的 dom 文档后调用,如下面的示例所示。
如果写入成功则返回写入的字节数,如果出错则返回 false
。
示例 #1 将 DOM 树保存到文件
<?php
$doc = new DOMDocument('1.0');
// 我们需要一个不错的输出
$doc->formatOutput = true;
$root = $doc->createElement('book');
$root = $doc->appendChild($root);
$title = $doc->createElement('title');
$title = $root->appendChild($title);
$text = $doc->createTextNode('This is the title');
$text = $title->appendChild($text);
echo 'Wrote: ' . $doc->save("/tmp/test.xml") . ' bytes'; // Wrote: 72 bytes
?>
我花了很长时间才发现
DOMDocument->formatOutput = true
只有在也设置了以下情况下,才会对从磁盘加载的文档产生影响
DOMDocument->preserveWhiteSpace = false ....
希望这能避免有人头疼。
XML 解析器将 XML 文档的文本转换为 UTF-8,即使您已设置 XML 的字符编码,例如作为 DOMDocument 构造函数的第二个参数。在使用 load() 命令解析 XML 后,其所有文本都已转换为 UTF-8。
如果您将特殊字符(例如变音符号)的文本节点附加到您的 XML 文档,因此您应该在将文本附加到文档之前使用 utf8_encode() 对您的文本进行 UTF-8 编码。否则,您会在 save() 命令处收到类似于“输出转换失败,原因是转换错误”的错误消息。请参见下面的示例
<?php
// 要插入到下面的 XML 中的文本
$txt = "a text with special characters like 'ä', 'ß', 'Ü' etc.";
// 创建 DOMDocument 实例
$dom = new DOMDocument;
// 加载 XML 文件
// 之前使用 DOMDocument('1.0', 'iso-8859-1') 创建
$dom = $dom->load("file.xml");
// 查找父节点
$parent = $dom->documentElement;
// 创建 DomXPath 实例
$xpath = new DomXPath($dom);
// 新节点将插入到此节点之前
$next = $xpath->query("//parentnode/childnode");
// 创建新的元素
$new_elem = $dom->createElement('new_elem');
// 插入新的元素
$parent->insertBefore($new_elem, $next->item(0));
// DOMXML = utf-8! (仅在 'save()' 时转换为 iso-8859-1)
// 避免在 'save()' 处出现错误消息“输出转换失败,原因是转换错误”
$txt = utf8_encode($txt);
// 使用 utf-8 编码的字符串创建新的文本节点
$nodetext = $dom->createTextNode("$txt");
// 将文本节点附加到新元素
$nodetext = $new_elem->appendChild($nodetext);
// 保存
$dom->save("file.xml");
?>
希望这能帮助到某些人。
siegparr
我只是想为 DOMDocument::save() 函数与 PHP serialize() 函数一起使用贡献我的一点微薄力量。
有时您可能需要在将 PHP 对象放入 XML 结构(或其他...)之前对其进行序列化。然后,我想您可能需要将此 XML 结构保存到文件中。当然,您还需要进一步读取此文件并将其反序列化才能使用其内容。
问题出现在要序列化的对象中存在一些被声明为受保护的属性时。
正如 PHP 文档中所述,序列化函数在这些受保护的属性之前添加一个星号,并在星号的每一侧添加一个 NULL 字符。
在这种情况下,DOMDocument::save 函数将在要保存的字符串中遇到的第一个 NULL 字符之前停止保存操作,因为 PHP 将其视为潜在风险。
因此,之后,文件的反序列化操作变得不可能。
为了解决这个问题,这里提供一个要应用的第一个解决方案
对于序列化,在 DOMDocument::save() 之前:
$data_serial = explode("\x00\x2A\x00", serialize($object)); // 去掉 'NULL * NULL' 字符串
$data_serial = implode("\x5C\x30\x2A\x5C\x30", $data_serial); // 并用 '\0*\0' 字符串替换
在反序列化之前
$data_serial = explode("\x5C\x30\x2A\x5C\x30", $serialized_object); // 去掉 '\0*\0' 字符串
$serial_object = implode("\x00\x2A\x00", $data_serial); // 并用之前序列化时包含的 'NULL * NULL' 字符串替换
第二个解决方案
对于序列化,在 DOMDocument::save() 之前
$serialized_object = addslashes(serialize($object)) ;
在应用程序中重新使用对象之前
$object = unserialize(stripslashes($serialized_object)) ;
希望这对大家有所帮助。
从头开始创建 DOMDocument 并保存时,即使声明为 iso-8859-1,编码也会是 utf-8。
加载声明并保存为 iso-8859-1 的 XML 文件时,php 会在保存更改后的文件时保留正确的编码。
php 将声明为 iso-8859-1 的文件在内部转换为 utf-8。 要添加包含特殊字符的文本,文本必须使用 utf-8 编码。 保存文档时,特殊字符将转换为 iso-8859-1。
要保存从头开始创建的 xml,请使用 fopen/fwrite 和 utf8_decode
$doc = new DOMDocument('1.0', 'iso-8859-1');
//使用适当的方法添加一些节点和文本
$f = fopen('xmlfile.xml', 'w+');
fwrite($f, utf8_decode($doc->saveXML()));
fclose($f);
我曾经因为无法保存编辑后的 XML 文件而苦恼不已,因为文件权限正常,但我知道它没问题。
最后我意识到,出于某种原因,当我尝试保存 XML 文件时,它会尝试将文件写入根目录。
因此,在加载 XML 文件时,使用 realpath() 来保留 XML 文件的完整系统路径。
<?php
$myfile = 'myxml.xml';
$myfile = realpath($myfile);
$doc = new DOMDocument('1.0');
$doc->load($myfile);
// 为了保险起见,我们添加两个元素
$root = $doc->documentElement;
$title = $doc->createElement('title');
$title = $root->appendChild($title);
$text = $doc->createTextNode('This is a title');
$text = $title->appendChild($text);
$doc->save($myfile);
?>
除了
DOMDocument->formatOutput = true
DOMDocument->preserveWhiteSpace = false
...你还要确保不要将文本节点添加为元素节点的同级节点,否则 formatOutput 无法正常工作。