功能特色
- 支援多維陣列遞迴轉換為合法 XML
- 第一層鍵值作為元素名稱,
elementName 指定根節點
- 純量值自動轉為 XML 屬性,陣列值轉為子元素
- 內建 XSL 樣式表連結支援
- 提供字串輸出與直接寫入檔案兩種介面
- 單例模式,輕量無依賴
類別完整代碼
class ArrayToXml {
private static $instance;
private function __construct() {}
public static function getInstance(): self {
if (!isset(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/** 產生 XML 字串
* @param array $data 轉換資料,第一個元素鍵為 elementName 時作為根節點名
* @param string $xsl 可選 XSL 檔案路徑
* @return string
*/
public function getXml(array $data, string $xsl = ''): string {
$xml = '';
if ($xsl) {
$xml .= '';
}
$xml .= $this->buildXml($data);
return $xml;
}
/** 遞迴建構 XML */
private function buildXml(array $data): string {
// 取得元素名稱
$elementName = 'item';
if (isset($data['elementName'])) {
$elementName = array_shift($data);
}
$xml = "<$elementName";
$hasChildren = false;
foreach ($data as $key => $value) {
if (!is_array($value)) {
// 純量值 -> 屬性
$xml .= ' ' . $key . '="' . htmlspecialchars((string)$value, ENT_QUOTES) . '"';
} else {
// 陣列值 -> 子元素
if (!$hasChildren) {
$xml .= '>';
$hasChildren = true;
}
$xml .= $this->buildXml($value);
}
}
if (!$hasChildren) {
$xml .= '>';
}
$xml .= "$elementName>";
return $xml;
}
/** 直接寫入檔案
* @return bool 成功與否
*/
public function write(string $filename, array $data, string $xsl = ''): bool {
$xml = $this->getXml($data, $xsl);
return file_put_contents($filename, $xml) !== false;
}
}
使用範例
$xml = ArrayToXml::getInstance();
$data = [
'elementName' => 'catalog', // 根節點名
'book' => [
'elementName' => 'book',
'id' => 'bk101', // 屬性
'title' => 'PHP 進階程式設計', // 屬性
'author' => [
'elementName' => 'author',
'name' => '王大明',
'email' => 'wang@example.com'
],
'chapters' => [
'elementName' => 'chapters',
'chapter' => [
['elementName' => 'chapter', 'num' => 1, 'title' => '基礎語法'],
['elementName' => 'chapter', 'num' => 2, 'title' => '物件導向'],
]
]
]
];
// 輸出字串
header('Content-Type: text/xml; charset=utf-8');
echo $xml->getXml($data);
// 或直接寫檔
$xml->write('catalog.xml', $data, 'style.xsl');
輸出 XML 範例
注意事項與限制
- 鍵名規則:陣列鍵需為合法 XML 標籤名(字母開頭、含字母數字底線連字號、無空格)
- 屬性順序:所有純量鍵值必須置於陣列「前段」,子元素陣列置於「後段」,否則會被誤判為屬性
- 特殊字元:已自動處理
< > & " ' 轉義
- CDATA 支援:若需輸出 HTML 片段,建議自行擴充
buildXml 偵測 cdata 鍵名
擴充建議
- 加入
namespace 與 schemaLocation 支援
- 實作
JsonSerializable 介面,直接 json_encode($xmlObj)
- 支援從 XML 反解回陣列(搭配
simplexml_load_string)