DOMDocument::saveXML

(PHP 5, PHP 7, PHP 8)

DOMDocument::saveXML将内部 XML 树转储回字符串

描述

public DOMDocument::saveXML(?DOMNode $node = null, int $options = 0): string|false

从 DOM 表示创建 XML 文档。此函数通常在从头开始构建新 dom 文档后调用,如以下示例所示。

参数

node

使用此参数仅输出特定节点,不包括 XML 声明,而不是整个文档。

options

附加选项。支持 LIBXML_NOEMPTYTAGLIBXML_NOXMLDECL 选项。在 PHP 8.3.0 之前,仅支持 LIBXML_NOEMPTYTAG 选项。

返回值

返回 XML,如果发生错误,则返回 false

错误/异常

DOM_WRONG_DOCUMENT_ERR

如果 node 来自另一个文档,则会引发此错误。

变更日志

版本 描述
8.3.0 现在支持 LIBXML_NOXMLDECL

示例

示例 #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
"Saving all the document:\n";
echo
$doc->saveXML() . "\n";

echo
"Saving only the title part:\n";
echo
$doc->saveXML($title);

?>

上面的示例将输出

Saving all the document:
<?xml version="1.0"?>
<book>
  <title>This is the title</title>
</book>

Saving only the title part:
<title>This is the title</title>

参见

添加笔记

用户贡献的笔记 17 个笔记

liumenglei0211 at 163 dot com
5 年前
如何在节点内容为空时显示两个标签。

<?php
$dom
= new \DOMDocument('1.0');
$document = $dom->createElement('document');
$document = $dom->appendChild($document);
$head = $dom->createElement('title','this is title');
$content = $dom->createElement('content','');
$document->appendChild($head);
$document->appendChild($content);
echo
$dom->saveXML();
?>

在 XML 中,它们被认为是完全相同的东西,任何解析器都应该识别这两种形式。但是,如果您仍然需要它,您可以这样写

<?php
echo $dom->saveXML($dom->documentElement, LIBXML_NOEMPTYTAG);
?>

示例 1:

<?xml version="1.0"?>
<document>
<title>this is title</title>
<content/>
</document>

示例 2:
<document>
<title>this is test</title>
<content></content>
</document>
devin at SPAMISBAD dot tritarget dot com
18 年前
花了一些时间才弄明白这一点。到目前为止,我在手册中没有看到太多关于解释此故障的内容。(对于 PHP5 我认为)

formatOutput = true; 当 DOM 的来源是通过 load() 从文件加载时似乎会失败。例如

<?php
$dom
= new DOMDocument();
$dom->load ("test.xml");
$dom->formatOutput = true;

$new_tag = $dom->createElement ('testNode');
$new_tag->appendChild (
$dom->createElement ('test', 'this is a test'));
$dom->documentElement->appendChild ($new_tag);

printf ("<pre>%s</pre>", htmlentities ($dom->saveXML()));
?>

不会缩进输出,并且会将修改后的节点显示在一长行中。在保存到文件时,会使编辑 config.xml 变得有点困难。

通过在 load() 之前添加 preserveWhiteSpace = false;,formatOutput 按预期工作。例如

<?php
$dom
= new DOMDocument();
$dom->preserveWhiteSpace = false;
$dom->load ("test.xml");
$dom->formatOutput = true;

$new_tag = $dom->createElement ('testNode');
$new_tag->appendChild (
$dom->createElement ('test', 'this is a test'));
$dom->documentElement->appendChild ($new_tag);

printf ("<pre>%s</pre>", htmlentities ($dom->saveXML()));
?>

注意:如果加载的 xml 文件(test.xml)有一个空的根节点,该节点没有缩写或没有子节点,则此方法将无法工作。

示例

无法工作
<?xml version="1.0"?>
<root>
</root>

可以工作
<?xml version="1.0"?>
<root/>

可以工作
<?xml version="1.0"?>
<root>
<!-- comment -->
</root>

可以工作
<?xml version="1.0"?>
<root>
<child/>
</root>
vikramvmalhotra at hotmail dot com
15 年前
如果在 XML 中存储多字节字符,那么使用 saveXML() 保存 XML 将会产生问题。它会输出以编码格式转换的字符。

<?php
$str
= domdoc->saveXML(); // 输出 "&x#1245;" 等编码数据
?>

请改为以下操作

<?php
$str
= domdoc->saveXML(domdoc->documentElement); // 输出 "保存しました" 等正确多字节数据
?>
mswiercz at mwerk dot com
19 年前
使用 DOM 生成文档时,可以快速减少内存消耗。

不要使用
$xmlStr = DOMDocument->saveXML();
echo $xmlStr;

将大型 DOM 转储到输出缓冲区,而是使用 PHP 输出流,例如:

DOMDocument->save('php://output');

生成大型 DOM 时,可以节省大量内存。
qjerry.com at gmail.com
15 年前
删除 XML 声明 (<?xml version="1.0" ... ?>) 的最简单(也可能是最快速)方法是单独输出 DOMDocument 的子节点

<?php

$document
= new DOMDocument();
$document->load('/some/file.xml');

// 这也会输出顶层的 doctype 和注释
foreach($document->childNodes as $node)
$result .= $document->saveXML($node)."\n";

echo
$result;

?>

在处理浏览器兼容性问题时,这可能很有用,例如,IE6 中关于有效 XHTML 的常见问题。
padys at tlen dot pl
20 年前
保存整个文档时
DOMDocument->saveXML() 生成的字符串的编码由 DOMDocument->encoding 属性定义。

仅保存一个节点时
DOMDocument->saveXML(DOMNode) 始终生成 UTF-8 编码的字符串。
JITR
17 年前
对 `devin at SPAMISBAD dot tritarget dot com''s 的帖子发表评论

感谢您指出 `formatOutput' 与 `load*()' 的陷阱。这确实让我避免了一些潜在的意外情况。

我认为这种看似奇怪的行为是可以解释的。警告:以下内容主要基于推断和实验。很少基于研究源代码和规范(我不确定有些内容是否能提供答案,至少不容易找到)。

正如您指出的,必须在从源字符串加载 DOM 之前设置 `preserveWhiteSpace'(我使用的是 `loadXML()',但我认为使用 `load()' 的情况应该是一样的)。这看起来合乎逻辑,因为此属性似乎控制解析和 DOM 创建过程,在此过程中包含空格的文本节点要么被包含,要么被丢弃。这可以通过转储 DOM 结构并比较基于 `preserveWhiteSpace' 值的结果来证明。如果将 `preserveWhiteSpace' 设置为 `FALSE',则返回的 DOM 中将不会存在包含空格的文本节点。如果此属性为 `TRUE',则这些节点将存在。

注意:在上一段中谈论空格时,我们肯定是在谈论所谓的“元素内容中的空格”或“元素内容空格”,如果我没弄错的话。另请参阅我在 `DOMText->isWhitespaceInElementContent()' 方法的注释中的评论。

至于 `saveXLM()' 输出的神秘影响,我认为其解释在于上述空格文本节点的存在与否。这也通过实验得到了证明:在将这样的节点添加到不包含任何节点的 DOM 中(该 DOM 是使用 `loadXML()' 创建的,并将 `preserveWhiteSpace' 设置为 `FALSE'),输出格式会受到影响,以至于在添加的节点之后,文档其余部分的格式会丢失。我认为空格文本节点的存在会强制执行这种渲染,即这些节点的内容用于分隔相邻节点,从而禁用默认格式。只有当不存在这样的文本节点时,输出格式才会生效(当然前提是将 `formatOutput' 设置为 `TRUE')。

嗯,我不太理解的是,你如何才能得到单行输出,而 `formatOutput' 设置为 `TRUE'。当不存在空格文本节点时(即,使用 `loadXML()' 加载 XML 并将 `preserveWhiteSpace' 设置为 `FALSE')以及将 `formatOutput' 设置为 *`FALSE'*(使用 `formatOutput' 的相反值,格式应该起作用,您不应该最终只得到一行)。但我没有看到您的源代码。也许您的 DOM 中包含没有换行的空格节点?

至于关于根元素的警告,我无论是在缩写形式还是完整形式中都没有看到空根元素存在任何问题。您所说的“可以工作”或“无法工作”是什么意思?
Alexander Fedulin
10 年前
正如 @fbernodi 早些时候所说,当您定义了多个命名空间时,DOMNode 的 saveXML 会出现问题。这是一个简单的解决方案

<code>
// $node 是某个其他文档的某个节点
$temp_document = new DOMDocument('1.0', 'utf-8');
$temp_document->appendChild($temp_document->importNode($node, true));
echo $temp_document->saveXML();
</code>
fbernoldi at gmail dot com
11 年前
您好,

我的一些解析代码遇到了意外的行为,因为此 saveXML 方法保存的标签没有命名空间规范。如果您尝试将从 DOMNode 保存的字符串加载到 DOMDocument 中,该 DOMNode 引用了命名空间,但该命名空间未在原始文档中的该元素中定义,则会得到一个格式错误的 xml。在示例中,您可以看到问题和可能的解决方案,另一个解决方案可能是为 ChildElement 节点添加命名空间引用 (<testNS:ChildElement testNS="http://example.org">),但在我的场景中不需要这样做。

<?php

// 测试 XML
$test_xml =
"<?xml version=\"1.0\"?>
<testNS:RootNode xmlns:testNS=\"http://example.org\">
<testNS:ChildElement>
<testNS:AnotherChildElement>I'm a Another Child node.</testNS:AnotherChildElement>
</testNS:ChildElement>
</testNS:RootNode>"
;

// 定义测试 DOMDocument
$domDoc = new DOMDocument("1.0");
$domDoc->loadXML($test_xml);

// 使用 xpath 搜索 ChildElement:
$domXPath = new DOMXPath($domDoc);
$domXPath->registerNamespace("testNS", "http://example.org");
$DOMNodeList_ChildElement = $domXPath->query("//testNS:RootNode/testNS:ChildElement");
$ChildElement = $DOMNodeList_ChildElement->item(0);

echo
"在另一个文档中加载不实用的 xml:\n\n";
echo
$domDoc->saveXML($ChildElement);

/* 这里输出:
*
* 在另一个文档中加载不实用的 xml:
*
* <testNS:ChildElement>
* <testNS:AnotherChildElement>I'm a Another Child node.</testNS:AnotherChildElement>
* </testNS:ChildElement>
*
*/

/**
* 函数帮助我们将元素克隆到另一个文档。
* @param DOMElement $node 要克隆的节点。
* @param DOMDocument $doc 将要引用元素的文档。
* @return DOMElement 新克隆的元素,没有命名空间。
*/
function cloneNode($node, $doc) {
// 使用原始的 localName(无命名空间)创建新元素
$nd = $doc->createElement($node->localName);

// 克隆属性
foreach($node->attributes as $value)
$nd->setAttribute($value->localName, $value->value);

// 没有更多子节点,则结束。
if (!$node->childNodes)
return
$nd;
// 我们有子节点,添加它们
foreach($node->childNodes as $child) {
if (
$child->nodeName=="#text") // 只需克隆文本节点,即文本注释、空格、制表符等。
$nd->appendChild($doc->createTextNode($child->nodeValue));
else
$nd->appendChild(cloneNode($child, $doc)); // 递归克隆所有子节点。
}
return
$nd;
}

// 新文档用于引用没有命名空间的新节点
$domDoc2 = new DOMDocument("1.0");

// 我们克隆此节点并去除命名空间
$new_node = cloneNode($ChildElement, $domDoc2);

echo
"\n\n我们可以毫无问题地将此加载到 DOMDocument 中:\n\n";
echo
$domDoc2->saveXML($new_node);

/*
* 我们可以毫无问题地将此加载到 DOMDocument 中:
*
* <ChildElement>
* <AnotherChildElement>I'm a Another Child node.</AnotherChildElement>
* </ChildElement>
*/

?>
xianrenb at gmail dot com
12 年前
如果你想保存 xhtml(在一个字符串中),你可以尝试以下方法
<?php
$doc
= new DOMDocument('1.0');

// ...

$xhtml = (string) $doc->saveXML($doc->doctype);
$xhtml .= "\n";
$xhtml .= (string) $doc->saveXML($doc->documentElement);
?>
Kriogen
16 年前
在测试之前创建 test.xml,使用
<?xml version="1.0" encoding="utf-8"?>
<Photos>
</Photos>

并将它粘贴到你的 php 文件之后

<?php
$simp
= simplexml_load_file('test.xml');
$node = $simp->addChild('home');
$node->addChild('mychild', 'insert text');
$s = simplexml_import_dom($simp);
$s->saveXML('test.xml');
?>

此代码在根目录中创建了一个子节点。
所有者 http://www.mensfashion.ru
samstah at gmail dot com
14 年前
我们发现使用 DOMDocument::saveHTML() 会将它转换为与 HTML 4.01 兼容的标记;而不是 XHTML。简单的答案是使用 saveXML(),尽管这会在顶部添加 XML 声明。

对于 qjerry.com at gmail.com,感谢你在下面提供的指针 - 但我认为最简单的方法似乎是使用
<?php $domDocument->saveXML($domDocument->documentElement); ?>

当然,如果你正在处理 XHTML,这也会从文档中删除任何 <!DOCTYPE> 声明。
shinsh at shinmugen dot net
16 年前
小心,这个函数在 5.2.6 版本中发生了变化。添加一个不是必需的必需参数绝不是最明智的想法,尤其是对于一个经常使用的函数来说。

如果出现错误,要修复你的程序,请这样填写第一个参数

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

为什么开发人员没有简单地将它实现为可选参数,而是将默认参数修复为 documentElement?
Sander
17 年前
请注意,对于大型 DOM 树(数万个元素嵌套至少几层深),当您调用 saveXML() 时,将 formatOutput 设置为 true 会将内存使用量提升到相当高的水平。(在 PHP 5.2.1 中测试)格式良好的输出不值得付出这种代价。
Anonymous
18 年前
我使用了“joe”发布的函数,但以下函数对我的获取 innerXML 有效
<?php
$itemLeido
= $XMLRespuesta->getElementsByTagName("articulos");
foreach(
$itemLeido as $node) {
echo(
$node->ownerDocument->saveXML($node));
}
?>
nevyn at NOSPAM dot email dot PLEASE dot it
17 年前
一个小函数,用于获取 Xml 节点的完整 xml 内容。

function innerXml($node)
{
$out = $node->ownerDocument->saveXML($node);
$re = "{^<(\\w*)(?:\\s*\\w+=(?:\"[^\"]*\"|\'[^\']*\'))*\\s*>(.*)</\\1>$}";
preg_match($re, $out, $mat);
return $mat[2];
}
Frank
7 年前
我想创建一个 DOM 文档 Xml 留言簿..能有人帮我吗?

用户名、表单中的评论读/写任务。

如果有人救了我,谢谢:)
To Top