在处理 (格式错误的) HTML 时,您可能最好使用 DOMDocument 的 saveHTML() 方法。C14N() 将尝试使您的 HTML 成为有效的 XML,例如通过将 <br> 转换为 <br></br>。
因此,不要使用
$html = $Node->C14N();
使用
$html = $Node->ownerDocument->saveHTML( $Node );
(PHP 5 >= 5.2.0, PHP 7, PHP 8)
DOMNode::C14N — 将节点规范化为字符串
$exclusive
= false
,$withComments
= false
,$xpath
= null
,$nsPrefixes
= null
将节点规范化为字符串
exclusive
启用仅对由提供的 xpath 或命名空间前缀匹配的节点进行排他解析。
withComments
在输出中保留注释。
xpath
一个 XPath 数组,用于按它们过滤节点。此数组中的每个条目都是一个关联数组,其中包含
query
键,其中包含 XPath 表达式作为字符串。
namespaces
键,其中包含一个数组,该数组将命名空间前缀(键)映射到命名空间 URI(值)。
nsPrefixes
一个用于按它们过滤节点的命名空间前缀数组。
返回规范化的节点作为字符串,或在失败时返回 false
示例 #1 带 XPath 查询的示例
此示例演示了通过 XPath 查询规范化和过滤节点的更高级用法。
<?php
$dom = new DOMDocument();
$dom->loadXML(<<<XML
<root xmlns:food="urn:food">
<!-- 冗余的命名空间声明将被规范化 -->
<food:fruit xmlns:food="urn:food">Apple</food:fruit>
<food:fruit>Orange</food:fruit>
<food:fruit>Pear</food:fruit>
<!-- 这里有蔬菜 -->
<food:vegetable>Lettuce</food:vegetable>
</root>
XML);
echo $dom->C14N(true, false, [
"query" => ".//f:fruit|.//f:fruit/text()",
"namespaces" => ["f" => "urn:food"],
]);
?>
上面的示例将输出
<food:fruit>Apple</food:fruit><food:fruit>Orange</food:fruit><food:fruit>Pear</food:fruit>
在处理 (格式错误的) HTML 时,您可能最好使用 DOMDocument 的 saveHTML() 方法。C14N() 将尝试使您的 HTML 成为有效的 XML,例如通过将 <br> 转换为 <br></br>。
因此,不要使用
$html = $Node->C14N();
使用
$html = $Node->ownerDocument->saveHTML( $Node );
如果节点未包含在文档树中,则 C14N() 返回空字符串
<?php
$d = new DOMDocument('1.0');
$d->loadXML('<foo></foo>');
$n = $d->createElement('bar');
var_dump($n->C14N());
$d->documentElement->appendChild($n);
var_dump($n->C14N());
?>
output
string(0) ""
string(11) "<bar></bar>"
[由 nielsdos 编辑:此问题已在 PHP 8.4 及更高版本中得到修复]
了解一下
<< 由于 PHP 中 XML 规范化存在已知问题,因此在 SimpleSAMLphp 中处理大型元数据文件会消耗大量资源,并且该量会随着元数据集中实体数量的平方而增加 >>
https://simplesamlphp.org/metaprocessing
<< C14N() 函数的运行时间似乎是 O(N^2)(或可能更糟?),具体取决于输入大小,这意味着随着输入的增长,它会变得非常慢。例如,一个包含大约 196000 个节点的输入大约需要 290 秒,而一个包含 486000 个节点的输入需要 2200 秒。>>
https://bugs.php.net/bug.php?id=53655
我们在 4.1 MB XML(105k 行)中遇到了相同的问题。票证 #53655 的示例代码需要 1 小时 36 分钟才能规范化它!