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

Eclipse 插件開發實戰:基於 WTP 打造自定義 JSP 編輯器(五)— 深度剖析 IStructuredModel 語義模型與 DOM 構建

     編輯:關於JSP

語法模型 (`IStructuredDocument`) 解決「文本結構」問題,語義模型 (`IStructuredModel`) 解決「業務含義」問題。本文深入剖析 `IStructuredModel` 的架構角色、模型句柄機制、基於 Document 的 DOM 構建流程、模型管理器協調邏輯,並揭示為什麼高級編輯功能(智能屬性提示、語義驗證、重構)必須依賴語義模型。

核心模型接口體系

IStructuredModel (公共模型接口)
├── getDocument() : IStructuredDocument          // 關聯的語法文檔
├── getModelState() : int                        // 模型狀態:UNLOADED, LOADING, LOADED, RECONCILING...
├── getModelListenerList() : ModelListenerList   // 監聽器管理
├── addModelListener / removeModelListener
└── getAdapter(Class) : Object                   // 適配器模式,獲取 IDOMDocument/ICSSDocument

IDOMDocument extends IStructuredModel            // XML/HTML/JSP 語義模型
├── getDocumentElement() : Element               // DOM 根元素
├── getElementById / getElementsByTagName...
└── 完整 W3C DOM Level 2/3 接口

ICSSDocument extends IStructuredModel            // CSS 語義模型 (WTP 自研,非標準 DOM)
└── getStylesheet() : CSSStyleSheet

模型句柄機制

`IStructuredModel` 實例不直接持有文檔內容,而是通過 **句柄** 間接引用:

interface IModelHandle {
    String getModelTypeId();        // 如 "org.eclipse.wst.xml.core.xmlsource"
    String getLocation();           // 文件路徑/URI
    long getModificationTime();     // 文件修改時間戳
    boolean isLoaded();             // 模型是否已載入內存
    IStructuredModel getModel();    // 獲取/觸發模型加載
}
  • 句柄輕量、可序列化、可跨進程傳遞。
  • 模型管理器 (`ModelManager`) 維護句柄 → 模型實例的緩存映射。
  • 編輯器持有句柄,按需獲取模型,實現**懶加載**與**共享**。

DOM 模型構建流程:從語法樹到語義樹

文本變更
    ↓
IDocumentPartitioner 增量分區 (語法區域更新)
    ↓
StructuredDocumentReconciler 協調器觸發
    ↓
IStructuredDocument 節點樹增量更新 (語法層)
    ↓
ModelBuilder 建構器 遍歷語法節點樹
    ↓
轉換規則引擎 (每種語言自定義)
    ├── HTML: HTMLTagRule, HTMLEntityRule...
    ├── JSP: JSPDirectiveRule, JSPScriptletRule, JSPActionRule...
    ├── XML: XMLDeclarationRule, XMLElementRule...
    └── CSS: CSSRuleSetRule, CSSPropertyRule...
    ↓
構建 W3C DOM 樹 (IDOMDocument)
    ├── Element 節點 → 對應語法 ELEMENT 節點
    ├── Attr 節點 → 對應語法 ATTRIBUTE 區域
    ├── Text/CDATA/Comment → 對應語法 TEXT/COMMENT 節點
    └── 命名空間解析、Schema 關聯、ID 屬性註冊
    ↓
ModelManager 緩存模型實例,通知 ModelListener
    ↓
編輯器功能消費模型:
    - Content Assist: 查詢 DOM 元素定義、屬性類型、枚舉值
    - Validator: 遍歷 DOM 核對 Schema/DTD、檢查必需屬性、嵌套規則
    - Hyperlink: 解析屬性值中的 URI、TLD 標籤定義、CSS 類定義
    - Formatter: 基於 DOM 結構重新序列化格式化

關鍵設計決策:為什麼 Document → Model 而非直接文本 → Model?

直接文本 → ModelDocument → Model (WTP 選擇)
需自行實現完整語法分析器(極其複雜)復用 SSE 成熟的分區器、協調器、節點樹
容錯性差:語法錯誤導致模型構建失敗語法層天然容錯(不完整標籤也有區域),模型構建可部分成功
增量更新極難實現語法層增量更新成熟,模型僅需處理受影響子樹
多語言混合 (JSP=HTML+Java+JSP標籤) 幾乎不可維護分區器天然分離語言區域,各語言 ModelBuilder 獨立處理

模型管理器協調邏輯

ModelManager (單例)
├── getModelForRead(IModelHandle) : IStructuredModel
│   └── 1. 緩存命中 → 返回
│   └── 2. 未命中 → 創建 ModelBuilder → 構建 → 緩存 → 返回
├── getModelForWrite(IModelHandle) : IStructuredModel
│   └── 獲取寫鎖,確保同一時刻僅一寫入者
├── releaseModel(IStructuredModel)
│   └── 引用計數歸零 → 可選釋放 (內存壓力時)
├── addModelListener / removeModelListener
└── 模型釋放策略:LRU + 內存閾值 + 文件修改時間檢查

JSP 特有模型構建細節

  • JSP 文件 = HTML 區域 + JSP 指令/腳本片段/動作標籤區域。
  • 模型構建器**並行處理**:HTML 區域由 `HTMLModelBuilder` 構建 DOM,JSP 區域由 `JSPModelBuilder` 構建特定語義節點(如 `JSPDirectiveNode`、`JSPScriptletNode`)。
  • 最終合成為統一的 `IDOMDocument`,JSP 節點作為 DOM 元素嵌入(命名空間 `https://java.sun.com/JSP/Page`)。
  • Java 代碼片段 (`<% ... %>`) **不構建 Java AST**,僅作為 `CDATA` 或特定文本節點保留(Java 模型由 JDT 獨立管理)。

為什麼高級功能需要語義模型?

功能僅靠語法模型 (Document)語義模型 (Model) 支撐
屬性值智能提示只知屬性名字符串,不知類型/枚舉查詢 Schema/DTD/TLD 獲取類型、枚舉、必填性
標籤嵌套驗證只知標籤匹配,不知語義父子關係基於 Schema/DTD 校驗嵌套合法性
跳轉到定義無法解析引用目標解析 TLD、XSD、CSS 類定義位置
重構 (重命名 ID/類)純文本替換,極易誤傷基於 DOM 節點精準重命名,更新所有引用
格式化基於縮進規則,不理解語義結構基於 DOM 樹結構智能換行、縮進、屬性排序

驗證模型理解:Model 分析視圖預告

下一篇將開發 `StructuredModelView`,可視化 `IDOMDocument` DOM 樹,對比語法樹差異,實時觀察:

  • 命名空間解析結果
  • Schema 類型標註(元素類型、屬性類型)
  • ID 屬性索引
  • 模型加載狀態變遷

這將徹底釐清「語法區域」與「語義節點」的邊界,為定制 Content Assist/Validator 奠定不可動搖的模型認知基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved