Expat 是基於事件的 XML 解析器 (非驗證、不建樹)。解析器將 XML 視為一連串事件:開始標籤、結束標籤、字元資料、處理指令等。開發者註冊回呼函數處理各事件,適合大型 XML、記憶體受限、只需提取特定資料的場景。PHP 核心內建,無需安裝。
| 函數 | 說明 |
|---|---|
xml_parser_create($encoding) | 建立解析器資源,可指定編碼 (UTF-8/ISO-8859-1/US-ASCII) |
xml_parser_free($parser) | 釋放解析器資源 |
xml_parse($parser, $data, $isFinal) | 解析資料塊,$isFinal 標記最後一塊 |
xml_set_element_handler($parser, $startFunc, $endFunc) | 設定開始/結束標籤回呼 |
xml_set_character_data_handler($parser, $func) | 設定字元資料回呼 |
xml_set_processing_instruction_handler($parser, $func) | 設定處理指令回呼 |
xml_set_default_handler($parser, $func) | 設定預設回呼 (未指定事件) |
xml_set_object($parser, $object) | 將解析器綁定到物件 (方法作為回呼) |
xml_get_error_code($parser) | 取得錯誤代碼 |
xml_error_string($code) | 錯誤代碼轉文字 |
xml_get_current_line_number($parser) | 取得當前行號 |
xml_get_current_column_number($parser) | 取得當前欄號 |
xml_parser_get_option($parser, $option) | 取得選項值 |
xml_parser_set_option($parser, $option, $value) | 設定選項 (如 XML_OPTION_CASE_FOLDING、XML_OPTION_TARGET_ENCODING) |
<?php
// 開始標籤
function startElement($parser, $name, $attrs) { ... }
// 結束標籤
function endElement($parser, $name) { ... }
// 字元資料
function characterData($parser, $data) { ... }
// 處理指令
function piHandler($parser, $target, $data) { ... }
?>
$attrs 為關聯陣列,鍵為屬性名,值為屬性值。
<?php
$parser = xml_parser_create('UTF-8');
function startElement($parser, $name, $attrs) {
switch ($name) {
case 'NOTE': echo "-- Note --<br>"; break;
case 'TO': echo "To: "; break;
case 'FROM': echo "From: "; break;
case 'HEADING': echo "Heading: "; break;
case 'BODY': echo "Message: "; break;
}
}
function endElement($parser, $name) {
echo "<br>";
}
function characterData($parser, $data) {
echo $data;
}
xml_set_element_handler($parser, 'startElement', 'endElement');
xml_set_character_data_handler($parser, 'characterData');
$fp = fopen('note.xml', 'r');
while ($data = fread($fp, 4096)) {
if (!xml_parse($parser, $data, feof($fp))) {
die(sprintf("XML Error: %s at line %d",
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser)));
}
}
fclose($fp);
xml_parser_free($parser);
/* 輸出:
-- Note --
To: Tove
From: Jani
Heading: Reminder
Message: Don't forget me this weekend!
*/
?>
<?php
class XMLParser {
private $parser;
private $depth = 0;
private $currentTag = '';
public function __construct($encoding = 'UTF-8') {
$this->parser = xml_parser_create($encoding);
xml_set_object($this->parser, $this);
xml_set_element_handler($this->parser, 'startElement', 'endElement');
xml_set_character_data_handler($this->parser, 'characterData');
}
public function parseFile($file) {
$fp = fopen($file, 'r');
while ($data = fread($fp, 4096)) {
if (!xml_parse($this->parser, $data, feof($fp))) {
throw new Exception(sprintf("XML Error: %s at line %d",
xml_error_string(xml_get_error_code($this->parser)),
xml_get_current_line_number($this->parser)));
}
}
fclose($fp);
}
public function __destruct() {
xml_parser_free($this->parser);
}
private function startElement($parser, $name, $attrs) {
$this->depth++;
$this->currentTag = $name;
echo str_repeat(' ', $this->depth) . "<$name>\n";
if ($attrs) {
foreach ($attrs as $k => $v) {
echo str_repeat(' ', $this->depth+1) . "$k=\"$v\"\n";
}
}
}
private function endElement($parser, $name) {
$this->depth--;
}
private function characterData($parser, $data) {
if (trim($data) !== '') {
echo str_repeat(' ', $this->depth+1) . "#text: $data\n";
}
}
}
$parser = new XMLParser();
$parser->parseFile('note.xml');
?>
xml_parse() 返回值,失敗時輸出 xml_error_string()、行號、欄號。xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0) 保留大小寫 (預設會轉大寫)。xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8') 確保輸出一致。