採用 PHP (數據層) → XML (中間數據格式) → XSLT (轉換邏輯) → HTML (展現層) 的管道架構,實現:
; php.ini
extension=php_domxml.dll ; XML DOM 操作核心
extension=php_xslt.dll ; XSLT 處理器 (基於 libxslt)
extension=php_iconv.dll ; 字符集轉換 (關鍵:GB2312 ↔ UTF-8)
致命坑點:PHP 安裝目錄下的 dlls/ 目錄必須加入系統 PATH 環境變量,否則 Apache 啟動報「找不到動態鏈接庫」。Linux 下需編譯安裝 libxslt、libxml2、libiconv 並指定 --with-xsl、--with-iconv。
; php.ini
include_path = ".;D:\php\pear" ; 指向 PEAR 安裝路徑
; 需安裝: DB.php (數據庫抽象), XML_SQL2XML (SQL→XML)
修改後必須重啟 Apache 生效,僅 reload 無效。
CREATE TABLE yhxx (
nsrnm VARCHAR(15) PRIMARY KEY, -- 納稅人代碼
qymc VARCHAR(200) NOT NULL, -- 企業名稱
qydh VARCHAR(50) -- 電話
) ENGINE=MyISAM DEFAULT CHARSET=gb2312;
browseData.php<?php
require_once "DB.php"; // PEAR DB 抽象層
// 數據庫連接配置
$dsn = "mysql://root:abcd@202.96.215.200/test";
$db = DB::connect($dsn);
if (DB::isError($db)) die($db->getMessage());
// 通用函數:讀取 XSL 模板
function readXsl($filename) {
if (!file_exists($filename)) die("模板文件 $filename 不存在");
return implode('', file($filename));
}
// 核心轉換函數:數據 + XSL → HTML
function getHtml($arydata, $xslstring) {
global $db;
include_once("XML/sql2xml.php"); // PEAR XML_SQL2XML
$sql2xml = new xml_sql2xml($db);
$sql2xml->setEncoding("GB2312"); // 指定輸出編碼
// 配置 XML 結構
$sql2xml->SetOptions([
'tagNameRow' => 'row',
'tagNameResult' => 'result'
]);
// 注入數據數組
$sql2xml->add($arydata);
$xmlstring = $sql2xml->getxml(); // 生成 XML 字符串
// XSLT 轉換
$arguments = [
'/_xml' => $xmlstring,
'/_xsl' => $xslstring
];
$xh = xslt_create();
$result = xslt_process($xh, 'arg:/_xml', 'arg:/_xsl', null, $arguments);
xslt_free($xh);
return $result ?: "XSLT 轉換失敗: " . xslt_error($xh);
}
// 業務邏輯:查詢數據
$sql = "SELECT nsrnm, qymc, qydh FROM yhxx";
$res = $db->query($sql);
if (DB::isError($res)) die("SQL 執行錯誤");
$data = [];
while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
$data[] = $row;
}
// 載入 XSL 模板並輸出
$htmlStr = readXsl("browseData.html"); // 實為 XSL 文件
echo getHtml($data, $htmlStr);
?>
browseData.html (實為 .xsl)<?xml version="1.0" encoding="gb2312"?>
<xsl:stylesheet version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="GB2312" indent="yes" />
<xsl:template match="/">
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>企業用戶信息列表</title>
</head>
<body>
<table border="1" cellpadding="0" cellspacing="0" style="border-collapse: collapse" width="100%">
<thead>
<tr style="background:#C0C0C0">
<th width="21%">納稅人代碼</th>
<th width="50%">企業名稱</th>
<th width="29%">聯繫電話</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="/result/row"> <!-- XPath 匹配 XML 結構 -->
<tr>
<td><xsl:value-of select="nsrnm" /></td>
<td><xsl:value-of select="qymc" /></td>
<td><xsl:value-of select="qydh" /></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="GB2312"?>
<result>
<row>
<nsrnm>310109040111985</nsrnm>
<qymc>喬家飲食發展有限公司</qymc>
<qydh>8621-63346626</qydh>
</row>
<row>...</row>
</result>
// 數據庫連接指定字符集 (MySQL 4.1+)
$db->query("SET NAMES gb2312"); // 或 utf8
// XML_SQL2XML 設置輸出編碼
$sql2xml->setEncoding("GB2312"); // 必須與 XSL output encoding 一致
// XSL 輸出聲明
<xsl:output method="html" encoding="GB2312" />
// PHP 輸出 Header
header("Content-Type: text/html; charset=gb2312");
鐵律:數據庫 → PHP → XML → XSL → 瀏覽器,**全鏈路編碼統一**,否則亂碼無解。
<?php
function xsl_date_format($timestamp) {
return date('Y-m-d H:i', $timestamp);
}
xslt_register_php_functions($xh); // 啟用 PHP 函數調用
?>
<!-- XSL 中調用 -->
<td><xsl:value-of select="php:function('xsl_date_format', created_at)" /></td>
$xslDom = domxml_open_file('template.xsl'); // 解析為 DOM
$xslDoc = xslt_process($xh, $xmlDom, $xslDom); // 直接用 DOM 避免重複解析
// 或使用 APCu/Redis 緩存 $xslstring
XML_SQL2XML 不支持流式處理,大數據集會導致內存爆炸。解決方案:
LIMIT 分頁XMLWriter 流式生成 XML| 痛點 | 現代替代方案 |
|---|---|
| XSLT 學習曲線陡峭、調試困難 | 模板引擎: Twig, Blade, Latte (語法直觀, IDE 支持完善) |
| PHP 8.x 移除 ext/xslt, 依賴 PECL 維護艱難 | 原生 PHP 模板 / 前端框架 (Vue/React) + API |
| XML 冗長, 解析性能差, 內存佔用高 | JSON 輕量高效, 配合 JSONPath/JQ 查詢 |
| PEAR 停止維護, 依賴鏈脆弱 | Composer + Packagist 現代依賴管理 |
| 服務端渲染阻塞, 首屏慢 | SSR (Next.js/Nuxt) / SSG / Island Architecture |
<?php
// Controller
$stmt = $pdo->query("SELECT nsrnm, qymc, qydh FROM yhxx LIMIT 20");
$companies = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo $twig->render('company/list.html.twig', ['companies' => $companies]);
{# company/list.html.twig #}
<table>
<thead><tr><th>代碼</th><th>名稱</th><th>電話</th></tr></thead>
<tbody>
{% for c in companies %}
<tr>
<td>{{ c.nsrnm }}</td>
<td>{{ c.qymc }}</td>
<td>{{ c.qydh }}</td>
</tr>
{% endfor %}
</tbody>
</table>
XML+XSLT 架構曾是企業級應用集成 (EAI) 的標準化選擇,體現了「數據與展現分離」的先進思想。但在 PHP 生態演進至今日,**擁抱 Composer、現代模板引擎、前後端分離** 才是理性選擇。理解這段歷史,是為了更好地設計未來——架構服務於業務,技術服務於架構,拒絕為技術而技術。