NotesXSLTransformer:用 LotusScript 以 XSLT 轉換 XML 與 DXL

NotesXSLTransformer:用 LotusScript 以 XSLT 轉換 XML 與 DXL

2026.07.19 約 1,009 字

一個外部系統丟給你一份 XML — 一批訂單、或一份 HR 名冊 — 而你要它變成 Notes 文件。問題是它的標籤結構跟你的表單欄位對不起來:進來的是 <order><customer>,你的表單要的是 CustNameOrderNo 這些欄位名。你可以寫一支逐欄 parse XML、再逐欄 doc.ReplaceItemValue 的迴圈 —— 或者,你用一張 XSLT stylesheet 把那份外部 XML 直接重塑成符合表單的 DXL,交給 NotesDXLImporter 建文件。做這個重塑的引擎,就是 NotesXSLTransformer —「DXL(Domino XML)資料透過 XSLT 的轉換」。它是 LotusScript XML 家族的最後一員,與 DOMSAX parser 並列,嵌進同一條以 stream 為基礎的 pipeline。同一個引擎也反過來用:把文件匯出成 DXL、再轉成別的系統要的格式送出去。

三步驟示意:外部系統送來的 <order> XML(標籤名跟表單對不起來)→ 一張 XSLT stylesheet 把 @id/customer/total 映射成 OrderNo/CustName/Amount → 產出符合 Order 表單的 DXL,由 NotesDXLImporter 建成 Notes 文件


重點摘要

  • 從 session 建立它:Set xsl = session.CreateXSLTransformer(input, styleSheet, output) — 三個參數都可選(可稍後用 SetInput / SetStyleSheet / SetOutput 設),然後呼叫 Process
  • stylesheet 必須是 NotesStream input 可以是 String、NotesStream、或另一個 XML processor(NotesDOMParser / NotesSAXParser / NotesDXLExporter);output 可以是 NotesStream、一個 parser、一個 NotesDXLImporter、或一個 NotesRichTextItem
  • 在交出去之前,別自己讀寫那些以檔案為底的 stream —「你不能在一個關聯到檔案的 NotesStream 物件被用作 XML 輸入或輸出之前,明確地讀或寫它」(檢查 Bytes 可以)。
  • 錯誤處理是透過 On Error + lsxbeerr.lss 常數與唯讀的 Log 屬性 — 沒有事件。(不同於 NotesSAXParser 會拋 SAX 事件處理器。)
  • Pipelining: 一個 XML 程序的輸出可以是下一個的輸入,所以你能把 NotesDXLExporterNotesXSLTransformerNotesDXLImporter 串起來、不落任何暫存檔。Release 6 新增;不支援 COM。

三 stream 的寫法

日常的形狀是三個 NotesStream — XML 輸入、XSL stylesheet、輸出 — 接進 transformer。這是官方範例(讀 hello.xml、套 hello.xsl、寫 hello.txt):

%INCLUDE "lsxbeerr.lss"
Sub Initialize
On Error lsERR_NOTES_XSLT_INPUT_OBJECT GoTo err_IN
On Error lsERR_NOTES_XSLT_OUTPUT_OBJECT GoTo err_OUT
On Error lsERR_NOTES_XSLT_STYLESHEET_OBJECT GoTo err_SS
Dim session As New NotesSession
Dim XML_in As NotesStream, XSL_ss As NotesStream, XML_out As NotesStream
Set XML_in = session.CreateStream
If Not XML_in.Open("c:\dxl\hello.xml") Then Exit Sub
If XML_in.Bytes = 0 Then Exit Sub ' 檢查 Bytes 是被允許的
Set XSL_ss = session.CreateStream
If Not XSL_ss.Open("c:\dxl\hello.xsl") Then Exit Sub ' stylesheet 必須是 stream
Set XML_out = session.CreateStream
If Not XML_out.Open("c:\dxl\hello.txt") Then Exit Sub
XML_out.Truncate ' 清掉舊輸出
Dim transformer As NotesXSLTransformer
Set transformer = session.CreateXSLTransformer(XML_in, XSL_ss, XML_out)
transformer.Process
Exit Sub
err_IN:
MessageBox "XSL Input error",, "XSLTransformer" : Exit Sub
err_OUT:
MessageBox "XSL Output error",, "XSLTransformer" : Exit Sub
err_SS:
MessageBox "Style Sheet error",, "XSLTransformer" : Exit Sub
End Sub

重要的習慣都在這裡:每個以檔案為底的 stream 都打開、但別自己讀寫它(檢查 Bytes = 0 確認輸入存在是唯一的例外)、Truncate 輸出 stream 好清掉舊內容、讓單一個 Process 跑完整個轉換。

錯誤走 Log,不走事件

這是這個類別跟它的 SAX 手足不同、也是一個錯誤假設會浪費時間的地方:NotesXSLTransformer 沒有事件模型。 沒有 XSLT_* 回呼要接。錯誤處理改成兩件事。第一,On Error 配上 %INCLUDE "lsxbeerr.lss" 帶進來的後端錯誤常數 — lsERR_NOTES_XSLT_INPUT_OBJECT_OUTPUT_OBJECT_STYLESHEET_OBJECT — 這就是官方範例區分「輸入問題」與「stylesheet 問題」的方式。第二,唯讀的 Log 屬性,「一個由 processor 產生的警告、錯誤、致命錯誤的 XML 表示」,你可以在 Process 之後讀它拿細節;ExitOnFirstFatalError 控制處理是否在第一個致命錯誤就停。如果你原本期待一個 SAX 式的處理器,這一段就是要重讀的。

Pipelining:跳過暫存檔

transformer 之所以把 parser 與 DXL 物件也當作 input/output、不只是 stream,原因是 pipelining —「把操作組合起來,讓一個 XML 程序的輸出成為另一個的輸入」。舉一個具體的:你要把一批文件從舊資料庫搬到一個表單設計不同的新資料庫,其中一個欄位改了名 —— 舊的叫 Cust,新表單要 CustomerName。與其寫 LotusScript 逐份文件複製、逐欄改名,你把三個物件串起來:

  • NotesDXLExporter(把舊庫文件匯出成 DXL)→ NotesXSLTransformer(stylesheet 把 <item name='Cust'> 改寫成 <item name='CustomerName'>)→ NotesDXLImporter(把改寫後的 DXL 寫進新庫)。

那支 stylesheet 做的就是這種節點層級的改寫:

<!-- 進來的 --> <item name='Cust'><text>Acme</text></item>
<!-- 出去的 --> <item name='CustomerName'><text>Acme</text></item>

欄位對應寫在宣告式的 stylesheet 裡,不寫在程式流程裡 —— 多一個欄位改名就多一條 template,不動 LotusScript。stylesheet 仍然是一個 NotesStream,但 XML 輸入與輸出變成活的物件,沒有任何中間檔碰到磁碟。AddParameter 讓你把最上層的 <xsl:param> 值傳進 stylesheet,所以同一個轉換能每次跑用不同參數(例如目標表單名、或一個批次代碼)。

同類別在其他語言

LotusScriptJavaSSJS / XPages
session.CreateXSLTransformer(...)NotesXSLTransformersession.createXSLTransformer(...)XSLTransformersession.createXSLTransformer(...)

Java 有一個對應的 lotus.domino.XSLTransformer,但它不是 1:1 鏡像 — Java 的 DXL/XSLT 路線用 JAXP 式的 result-target 模型(XSLTResultTarget,由 FileOutputStreamStringWriter 建構),而非那個 stream 三件組。SSJS 透過 session 取到同一個後端工廠方法。核心概念 — 餵 XML/DXL 與一個 stylesheet、拿到轉換後的輸出、優先用 pipelining 而非暫存檔 — 在三種語言都通用。

參考來源

← 回到文章列表