| 場景 | 解析器 | 理由 |
| 編輯器載入/儲存、樹形結構操作 | JDOM (DOM) | 記憶體樹可隨意增刪改查,配合 JTree 雙向同步 |
| 書籤樹構建 (大檔案、單向遍歷) | SAX + Stack | 流式處理、低記憶體、Stack 維護父子關係輸出 Bookmark 物件樹 |
3. Swing 編輯器實作要點
JTree 配合 DefaultTreeModel 顯示 XML 階層
- 節點物件包裝 JDOM
Element,雙向綁定:樹操作 → 更新 Element → 序列化回 XML
- 拖曳排序:
TransferHandler 實作移動節點邏輯
- 右鍵選單:新增/刪除/重命名章節、關聯 URL ID
4. C# 元件:HTML → PDF 單頁轉換
- 基於
WebBrowser 控制項 (IE Trident / Edge WebView2) 列印至 PDF 印表機驅動
- 優點:100% 瀏覽器渲染保真 (CSS3、JS 執行、WebFont、SVG)
- 缺點:需 Windows 環境、有浮水印、多執行緒下
WebBrowser 單執行緒套間 (STA) 導致不穩定
- 妥協:批次檔循序啟動 C# 執行檔,逐個處理 URL,避開併發問題
5. iText 5.x:PDF 合併與書籤注入
PdfCopy / PdfSmartCopy 合併單頁 PDF,保留字體嵌入、註解、表單
- 書籤構建:遞歸遍歷 SAX 解析產出的
BookmarkNode 樹,調用 PdfOutline API
- 支援書籤屬性:標題、目標頁碼、縮放模式 (FitH/FitV/XYZ)、文字顏色/樣式
- 效能優化:
PdfSmartCopy 重複資源去重;大檔案分批合併避免 OOM
6. 自訂類別載入器:免配置啟動
- 問題:工具依賴 20+ JAR (iText, JDOM, SwingX, ...),用戶不應手動設定 CLASSPATH
- 方案:主 JAR
MANIFEST.MF Class-Path 相對路徑 不夠靈活 (路徑固定、無法動態發現)
- 實作:
URLClassLoader 子類掃描 lib/ 目錄所有 .jar,addURL 註冊,設為執行緒上下文類別載入器
- 啟動腳本:
java -jar h2p-tool.jar 即可,無需任何環境變數
7. JVM 記憶體參數調優
-Xmx512m -Xms512m
-XX:+UseParallelGC
-XX:MaxMetaspaceSize=128m
- 合併 50+ 頁 PDF 易觸發
OutOfMemoryError: Java heap space
- 固定堆大小避免擴縮容抖動;並行 GC 減少停頓
- 批次檔統一注入參數,確保 C# 子進程與 Java 主進程記憶體隔離
8. 字元編碼與流處理細節
- 全鏈路強制 UTF-8:XML 讀寫、C# 進程標準輸出/錯誤、iText 字串
- 大檔案流式複製:
BufferedInputStream/OutputStream 8KB 緩衝,避免全量載入記憶體
- 臨時檔清理:
shutdownHook / try-with-resources 確保中斷時殘留檔案被刪除
架構圖解
[使用者] → [Swing GUI] ↔ [JDOM XML Model] ↔ [href/outline.h2p.xml]
↓
[批次轉換控制器]
↓
┌───────────┴───────────┐
↓ ↓
[ProcessBuilder] [SAX Parser + Stack]
→ C# Converter.exe → Bookmark Tree
↓ ↓
{id}.pdf (單頁) ──────→ [iText PdfSmartCopy]
↓ ↓
└───────────┬───────────┘
↓
最終 PDF (含書籤)
總結
H2P Tool 看似技術雜湊,實則每個選型都有明確工程理由:
- DOM 編輯、SAX 解析 —— 適場景分離
- C# WebBrowser —— 渲染保真無替代
- iText 書籤 API —— 功能最完整
- 自訂 ClassLoader —— 用戶體驗優先
- 批次檔編排 —— 規避異構併發坑
這正是「在約束中尋找最優解」的典型桌面工具工程實踐。
- 上一篇文章: H2P 方案演進展望:從完整網頁還原走向純內容提取
- 下一篇文章: 整合 Java 內容倉庫 (JCR) 與 Spring 框架:實作指南
Copyright ©
程式碼之家 All Rights Reserved