我花了很長時間才發現
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'; // 寫入:72 位元組
?>
我花了很長時間才發現
DOMDocument->formatOutput = true
只會對從磁碟載入的文件產生影響,如果同時設定
DOMDocument->preserveWhiteSpace = false ....
希望這可以幫其他人省點麻煩。
即使您設定了 XML 的字元編碼(例如,作為 DOMDocument 建構函式的第二個參數),XML 解析器也會將 XML 文件的文字轉換為 UTF-8。使用 load() 命令解析 XML 後,其所有文字都已轉換為 UTF-8。
如果您要將包含特殊字元(例如變音符號)的文字節點附加到 XML 文件中,則應事先使用 utf8_encode() 將文字轉換為 UTF-8,然後再將文字附加到文件中。否則,您會在 save() 命令執行時收到類似「由於轉換錯誤,輸出轉換失敗」的錯誤訊息。請參閱以下範例
<?php
// 要插入下方 XML 的文字
$txt = "包含特殊字元(例如 'ä'、'ß'、'Ü' 等)的文字";
// 建立 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 結構儲存到檔案中。當然,您之後需要讀取此檔案並將其反序列化才能使用其內容。
當要序列化的物件中有一些屬性被宣告為 Protected 時,就會出現問題。
正如 PHP 文件中所述,serialize 函式會在這些 protected 屬性的名稱前後加上星號,並在星號的兩側加上 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 並儲存時,編碼將會是 utf-8,即使它被宣告為 iso-8859-1。
載入宣告並儲存為 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() 保留完整的系統路徑。
<?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);
?>