當處理(格式錯誤的)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());
?>
輸出
字串(0) ""
字串(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 分鐘才能將其規範化!