CREATE 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)
);
<?php
$conn = mysql_connect("localhost", "root", "");
mysql_select_db("bbs", $conn);
$query = "SELECT * FROM books ORDER BY bookid";
$rs = mysql_query($query, $conn);
$num_fields = mysql_num_fields($rs);
$xml = '<?xml version="1.0" encoding="GB2312"?>' . "\n";
$xml .= '<books>' . "\n";
while ($row = mysql_fetch_array($rs)) {
for ($i = 0; $i < $num_fields; $i++) {
$field_name = mysql_field_name($rs, $i);
$xml .= "<$field_name>" . htmlspecialchars($row[$i]) . "</$field_name>\n";
}
}
mysql_free_result($rs);
mysql_close($conn);
$xml .= '</books>';
$fp = fopen("xmldoc/xmldoc.xml", "w");
if (fwrite($fp, $xml)) {
echo "XML 寫入成功!";
} else {
echo "XML 寫入失敗!";
}
fclose($fp);
?>
<?php
class XMLParser {
var $parser;
function __construct() {
$this->parser = xml_parser_create();
xml_set_object($this->parser, $this);
xml_set_element_handler($this->parser, "tag_open", "tag_close");
xml_set_character_data_handler($this->parser, "cdata");
}
function parse($data) {
xml_parse($this->parser, $data);
}
function tag_open($parser, $tag, $attrs) {
$line = xml_get_current_line_number($parser);
if ($line == 2) { // 根節點
echo "<tr><td colspan=2 align=center>$tag</td></tr>";
} else {
$mod = ($line - 2) % 6;
$labels = ['下載', 'ID號', '書名', '作者', '出版社', '出版日期'];
echo "<tr><td>{$labels[$mod]}</td><td>";
}
}
function cdata($parser, $cdata) {
echo $cdata;
}
function tag_close($parser, $tag) {
echo "</td></tr>\n";
}
}
$parser = new XMLParser();
$xml_data = file_get_contents("xmldoc/xmldoc.xml");
?>
<table border=1 cellspacing=1 cellpadding=2 width=80% bgcolor=#b0d8ff align=center>
<?php $parser->parse($xml_data); ?>
</table>
| 問題 | 原因 | 改進 |
|---|---|---|
| 每欄位獨立成行,非一書一列 | SAX 逐節點處理,缺乏層級上下文 | 改用 DOMDocument 或 SimpleXML,以 <book> 為單位迴圈 |
| 硬編碼欄位順序(%6 邏輯) | 強依賴 SELECT 欄位順序 | 明確建立 <book> 父節點包裹各欄位 |
| 無法處理屬性、巢狀結構 | 簡易 SAX 範例限制 | DOMDocument 支援完整 XPath、屬性、命名空間 |
| 編碼宣告 GB2312 但資料可能 UTF-8 | 編碼不一致導致亂碼 | 統一 UTF-8,xml_parser_create('UTF-8') |
<?php
// 生成 XML
$books = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><books/>');
$pdo = new PDO("mysql:host=localhost;dbname=bbs;charset=utf8", "root", "");
$stmt = $pdo->query("SELECT * FROM books ORDER BY bookid");
foreach ($stmt as $row) {
$book = $books->addChild('book');
foreach ($row as $key => $val) {
if (is_numeric($key)) continue; // 跳過數字索引
$book->addChild($key, $val);
}
}
$books->asXML('xmldoc/books.xml');
// 解析輸出 HTML
$xml = simplexml_load_file('xmldoc/books.xml');
echo "<table><tr><th>ID</th><th>書名</th><th>作者</th><th>出版社</th><th>出版日期</th><th>下載</th></tr>";
foreach ($xml->book as $book) {
echo "<tr>";
echo "<td>{$book->bookid}</td>";
echo "<td>{$book->bookname}</td>";
echo "<td>{$book->bookauth}</td>";
echo "<td>{$book->bookpublisher}</td>";
echo "<td>{$book->bookpubdate}</td>";
echo "<td><a href='{$book->bookurl}'>下載</a></td>";
echo "</tr>";
}
echo "</table>";
?>
原始範例展示了「資料庫 → XML 檔案 → SAX 解析 → HTML」完整鏈路,但 SAX 事件驅動模型缺乏結構上下文,導致輸出邏輯僵硬。現代 PHP 開發強烈建議使用 SimpleXML(輕量、直觀)或 DOMDocument(功能完整、支援 XPath/XSLT)替代手寫 SAX 解析器,代碼量減少 80% 且健壯度大幅提升。