books 資料表xmldoc/xmldoc.xmlxml_parser_create() (SAX 事件驅動) 解析並輸出 HTMLCREATE TABLE books (
bookid INT(4) NOT NULL AUTO_INCREMENT,
bookname VARCHAR(100) NOT NULL,
bookauth VARCHAR(50) NOT NULL,
bookpublisher VARCHAR(50) NOT NULL,
bookpubdate DATETIME NOT NULL,
bookurl VARCHAR(50) NOT NULL,
PRIMARY KEY (bookid)
);
generate_xml.php<?php
$conn = mysql_connect('localhost', 'root', '');
mysql_select_db('bbs', $conn);
$query = "SELECT * FROM books ORDER BY bookid";
$rs = mysql_query($query, $conn);
$numFields = mysql_num_fields($rs);
$xml = '<?xml version="1.0" encoding="GB2312"?> ';
$xml .= '<books> ';
while ($row = mysql_fetch_array($rs)) {
for ($i = 0; $i < $numFields; $i++) {
$fieldName = mysql_field_name($rs, $i);
// 注意:欄位值需跳脫 XML 特殊字元
$value = htmlspecialchars($row[$i], ENT_QUOTES, 'GB2312');
$xml .= "<$fieldName>$value</$fieldName> ";
}
}
mysql_free_result($rs);
mysql_close($conn);
$xml .= '</books> ';
$fp = fopen('xmldoc/xmldoc.xml', 'w');
if (fwrite($fp, $xml)) {
echo "XML 檔案寫入成功!";
} else {
echo "寫入失敗!";
}
fclose($fp);
?>
注意:原始碼未對值做 htmlspecialchars,實務必加上防止 <, >, & 破壞 XML 結構。
parse_xml.php (SAX 解析器)<?php
class XMLParser {
var $parser;
var $currentTag = '';
var $currentData = '';
var $books = [];
var $currentBook = [];
function __construct($xmlFile) {
$this->parser = xml_parser_create();
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, 1);
xml_set_object($this->parser, $this);
xml_set_element_handler($this->parser, 'startElement', 'endElement');
xml_set_character_data_handler($this->parser, 'characterData');
$data = file_get_contents($xmlFile);
if (!xml_parse($this->parser, $data)) {
die(sprintf("XML 錯誤: %s at line %d",
xml_error_string(xml_get_error_code($this->parser)),
xml_get_current_line_number($this->parser)
));
}
xml_parser_free($this->parser);
$this->outputHtml();
}
function startElement($parser, $name, $attrs) {
$this->currentTag = $name;
if ($name === 'bookid') {
$this->currentBook = [];
}
}
function characterData($parser, $data) {
if ($this->currentTag && $this->currentTag !== 'books') {
$this->currentBook[$this->currentTag] = $data;
}
}
function endElement($parser, $name) {
if ($name === 'bookid') {
$this->books[] = $this->currentBook;
}
$this->currentTag = '';
}
function outputHtml() {
echo "<table border='1' cellpadding='5' cellspacing='0'>";
echo "<tr><th>ID</th><th>書名</th><th>作者</th><th>出版社</th><th>出版日期</th><th>連結</th></tr>";
foreach ($this->books as $book) {
echo "<tr>";
echo "<td>" . htmlspecialchars($book['bookid']) . "</td>";
echo "<td>" . htmlspecialchars($book['bookname']) . "</td>";
echo "<td>" . htmlspecialchars($book['bookauth']) . "</td>";
echo "<td>" . htmlspecialchars($book['bookpublisher']) . "</td>";
echo "<td>" . htmlspecialchars($book['bookpubdate']) . "</td>";
echo "<td><a href='" . htmlspecialchars($book['bookurl']) . "' target='_blank'>連結</a></td>";
echo "</tr>";
}
echo "</table>";
}
}
new XMLParser('xmldoc/xmldoc.xml');
?>
| 特性 | SAX (xml_parser) | DOM (DOMDocument) |
|---|---|---|
| 記憶體 | 極低 (串流) | 載入整份文件 |
| 速度 | 快 | 較慢 |
| API 風格 | 事件驅動 (callback) | 樹狀物件操作 |
| 適合場景 | 大型 XML、單向讀取 | 需隨機存取、修改、XPath 查詢 |
| 錯誤處理 | 需自行處理 | libxml_use_internal_errors() |
XMLReader (Pull Parser, PHP 5.1+)<?php
$reader = new XMLReader();
$reader->open('xmldoc/xmldoc.xml');
echo "<table border='1'><tr><th>ID</th><th>書名</th><th>作者</th><th>出版社</th><th>日期</th><th>連結</th></tr>";
while ($reader->read()) {
if ($reader->nodeType === XMLReader::ELEMENT && $reader->name === 'bookid') {
// 讀取完整 節點
$bookXml = $reader->readOuterXml();
$bookDom = new DOMDocument();
$bookDom->loadXML($bookXml);
$id = $bookDom->getElementsByTagName('bookid')->item(0)->textContent;
$name = $bookDom->getElementsByTagName('bookname')->item(0)->textContent;
$auth = $bookDom->getElementsByTagName('bookauth')->item(0)->textContent;
$pub = $bookDom->getElementsByTagName('bookpublisher')->item(0)->textContent;
$date = $bookDom->getElementsByTagName('bookpubdate')->item(0)->textContent;
$url = $bookDom->getElementsByTagName('bookurl')->item(0)->textContent;
echo "<tr><td>$id</td><td>$name</td><td>$auth</td><td>$pub</td><td>$date</td><td><a href='$url'>連結</a></td></tr>";
}
}
echo "</table>";
$reader->close();
?>
優點:記憶體效率如 SAX,API 如 DOM 直觀,支援 readOuterXml() 取得片段再交給 DOM 處理。
本文展示「MySQL → 字串拼接 XML → 檔案 → SAX 解析 → HTML」完整流程。雖然字串拼接 XML 簡單,但生產環境強烈建議使用 DOMDocument 或 XMLWriter 產生 XML,自動處理編碼、跳脫、格式化。解析端則視檔案大小與需求選擇 SAX (大檔/單向)、DOM (小檔/隨機存取) 或 XMLReader (折衷)。