早期專案資料量不足,需從合作方的 Web Search 介面拉取 XML 資料並轉為 HTML 呈現。專案基於 PHP 4,且伺服器未啟用 DOM 擴展(PHP 5 才完善支援 DOM),因此採用內建的 XML Parser (SAX 模式) 進行事件驅動解析。
XML Parser 採流式讀取,記憶體佔用極低,適合大型 XML。解析過程由三類事件觸發對應回調函式:
| 事件類型 | 設定函式 | 觸發時機 |
|---|---|---|
| 元素開始/結束 | xml_set_element_handler() | 遇到 <tag> / </tag> |
| 字元資料 (CDATA) | xml_set_character_data_handler() | 標籤間的文字內容 |
| 處理指令/外部實體/記法宣告等 | 對應 xml_set_*_handler() | 較少用,視需求掛載 |
<?php
$parser = xml_parser_create(); // 建立解析器
xml_set_element_handler($parser, "startElement", "endElement");
xml_set_character_data_handler($parser, "characterData");
$xml_file = "1.xml"; // 可為本地路徑或 URL
$fp = fopen($xml_file, "r");
while ($data = fread($fp, 4096)) {
xml_parse($parser, $data, feof($fp)); // 分塊解析,最後一塊 is_final=true
}
fclose($fp);
xml_parser_free($parser);
// ---- 回調函式實作 ----
function startElement($parser, $name, $attrs) {
echo "開始標籤: $name
";
if ($attrs) print_r($attrs);
}
function endElement($parser, $name) {
echo "結束標籤: $name
";
}
function characterData($parser, $data) {
$data = trim($data);
if ($data) echo "文字資料: $data
";
}
?>
xml_parse() 第三參數 is_final 必須在最後一塊傳 true,否則結構不完整會報錯。iconv() 轉 UTF-8 再餵給 Parser。$name 會包含前綴(如 ns:tag),需自行切分。strtolower()。| 方案 | PHP 版本 | 記憶體 | 易用度 | 適用場景 |
|---|---|---|---|---|
| XML Parser (SAX) | 4.0+ | 極低 (流式) | 中 (事件回調) | 超大 XML、記憶體受限 |
| SimpleXML | 5.0+ | 中 (樹狀) | 高 (物件屬性存取) | 中小型 XML、快速開發 |
| DOMDocument | 5.0+ | 高 (完整樹) | 中高 (XPath、修改) | 需修改/查詢複雜結構 |
| XMLReader | 5.1+ | 極低 (拉式) | 中高 (游標 API) | 大型 XML、單向讀取 |
雖然 PHP 4 時代的 XML Parser 代碼較繁瑣,但理解其事件驅動、流式解析的核心機制,對後續學習 XMLReader、甚至 Node.js 的 sax-js、Python 的 xml.sax 皆有遷移價值。維護舊專案時,若無法升級 PHP 版本,此法仍是最穩健選擇。