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

PHP XML Expat 解析器完整教學:事件驅動解析

     編輯:PHP 入門

PHP XML Expat 解析器完整教學:事件驅動解析


簡介

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 為關聯陣列,鍵為屬性名,值為屬性值。


完整範例:解析 note.xml

<?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');
?>

特性與限制

  • 優點: 記憶體用量極低、速度快、支援超大檔案、不需載入整份文檔。
  • 缺點: 無法隨機存取節點、難以進行複雜結構修改、不支援驗證 (DTD/XSD)、需自行管理狀態 (如深度、父子關係)。
  • 適用場景: 大型 XML 匯入、日誌分析、提取特定標籤資料、串流處理。

錯誤處理最佳實踐

  • 解析循環中檢查 xml_parse() 返回值,失敗時輸出 xml_error_string()、行號、欄號。
  • 確保 XML 為 Well-formed,否則 Expat 會報錯 (不檢查 DTD 有效性)。
  • 使用 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0) 保留大小寫 (預設會轉大寫)。
  • 指定目標編碼 xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8') 確保輸出一致。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved