首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 數組轉 XML 通用類:基於 XMLWriter 的高性能遞歸生成方案

     編輯:PHP 相關知識

為什麼選 XMLWriter?

  • **流式寫入**:不構建完整 DOM 樹,內存佔用極低,適合大數據導出。
  • **自動轉義**:自動處理特殊字符 (< > & " ') 和編碼聲明。
  • **性能優異**:C 底層實現,比手動拼接字符串或 DOMDocument 快數倍。
  • **標準擴展**:PHP 5.1.2+ 內置,無需額外安裝。

通用轉換類 A2Xml

<?php
class A2Xml {
    private $version = '1.0';
    private $encoding = 'UTF-8';
    private $rootName = 'root';
    private $writer;

    public function __construct(string $rootName = 'root', string $encoding = 'UTF-8', string $version = '1.0') {
        $this->rootName = $rootName;
        $this->encoding = $encoding;
        $this->version  = $version;
        $this->writer   = new XMLWriter();
    }

    /**
     * 數組轉 XML 字符串
     * @param array  $data      待轉換數組 (支持多維嵌套)
     * @param bool   $pretty    是否格式化縮進 (默認 true)
     * @return string XML 字符串
     */
    public function toXml(array $data, bool $pretty = true): string {
        $this->writer->openMemory();
        $this->writer->setIndent($pretty);
        $this->writer->setIndentString('  ');
        $this->writer->startDocument($this->version, $this->encoding);
        $this->writer->startElement($this->rootName);

        $this->writeNode($data);

        $this->writer->endElement(); // root
        $this->writer->endDocument();
        return $this->writer->outputMemory(true);
    }

    private function writeNode(array $data): void {
        foreach ($data as $key => $value) {
            // 鍵名合法化:XML 標簽不能以數字/特殊字符開頭
            $tag = preg_replace('/^[^a-zA-Z_]/', '_$0', $key);
            $tag = preg_replace('/[^a-zA-Z0-9_.-]/', '_', $tag);

            if (is_array($value)) {
                $this->writer->startElement($tag);
                $this->writeNode($value); // 遞歸
                $this->writer->endElement();
            } elseif (is_bool($value)) {
                $this->writer->writeElement($tag, $value ? 'true' : 'false');
            } elseif ($value === null) {
                $this->writer->writeElement($tag, ''); // 或寫 xsi:nil="true"
            } else {
                $this->writer->writeElement($tag, (string)$value);
            }
        }
    }
}
?>

使用示例

<?php
$data = [
    'order' => [
        'id' => 1001,
        'customer' => ['name' => '張三', 'email' => 'zhang@example.com'],
        'items' => [
            ['sku' => 'A001', 'qty' => 2, 'price' => 99.00],
            ['sku' => 'A002', 'qty' => 1, 'price' => 149.00],
        ],
        'paid' => true,
        'note' => null,
    ]
];

$xml = new A2Xml('order');
echo $xml->toXml($data);
/* 輸出:


  1001
  
    張三
    zhang@example.com
  
  
    
      A001
      2
      99
    
    
      A002
      1
      149
    
  
  true
  

*/
?>

關鍵細節處理

問題解決方案
數字鍵名 (0,1,2...)XML 標簽不能以數字開頭,自動加前綴 _0、_1 或統一用 item (需檢測連續數字索引)
特殊字符鍵名正則替換非法字符為下劃線
布爾值轉為 true/false 字符串
NULL 值輸出空元素或 xsi:nil="true"
CDATA 區塊含 HTML/腳本內容時調用 writeCData(),可添加 @cdata 鍵名約定自動識別

進階:數字索引自動包裹為


private function writeNode(array $data): void {
    $isList = array_keys($data) === range(0, count($data)-1);
    foreach ($data as $key => $value) {
        $tag = $isList ? 'item' : $this->sanitizeTag($key);
        // ... 同前
    }
}
private function sanitizeTag(string $key): string {
    return preg_replace('/[^a-zA-Z0-9_.-]/', '_', ltrim($key, '0-9'));
}

對比:手動拼接 vs DOMDocument vs XMLWriter

方案內存速度安全性推薦度
字符串拼接高 (全量)快 (小數據)極低 (易注入、編碼錯誤)❌ 禁用
DOMDocument高 (構建樹)中高✅ 小數據、需後續操作 DOM
XMLWriter**極低 (流式)****最快**高 (自動轉義)✅✅✅ **首選**
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved