XRX/XForms 生成器
您擁有一個 XML 模式,並希望直接從 XML 模式自動生成 XForms 應用程式。
我們將編寫一個 XQuery,它將以 XML 模式的 URL 作為輸入,並生成 XForms 編輯表單作為輸出。
注意:本示例中的一些函式依賴於使用 ISO/IEC 元素命名約定來“猜測”要放置在 XForms 應用程式上的正確控制元件。作為替代方案,您可以在 XML 模式的註釋中新增標籤,以便始終從 XML 模式生成正確的 XForms 控制元件。此選項的缺點是您將被迫使用文字編輯器而不是圖形編輯器來編輯您的 XML 模式。
以下是用於生成 XForms 應用程式的步驟
- 解析 XML 模式檔案,查詢文件根節點
- 開始為 XML 模式中的每個複雜元素生成 xf:groups
- 對於每個 simpleType,猜測要使用的適當 XForms 控制元件。使用來自 XML 資料型別或元素名稱的提示來猜測正確的控制元件型別。利用 ISO/IEC 11179 元資料登錄檔命名約定和 表示項 (如果可能)。對於簡單文字欄位,使用 xf:input,但對於列舉值,使用 xf:select1。例如,如果元素名稱的字尾是 text、description 或 note,則使用 textarea 控制元件。
- 在 XForms 模型的繫結部分生成任何業務規則。雖然未來的 XForms 客戶端可能能夠從 XML 模式中自動推斷規則,但目前許多 XForms 客戶端並不完全支援 XML 模式。因此,要生成所有必填欄位的列表,必須生成一組繫結元素。幸運的是,這隻需要幾行 XQuery 程式碼。
- 為表單的初始值生成一個例項文件
我們將利用大量 XQuery 函式來保持我們的主要 XQuery 簡單。一個單獨的模組將用於儲存所有這些函式。
然後可以使用特定行為自定義生成的 XForms 應用程式。完成此操作後,如果 XML 模式發生更改,您必須重新生成 XForms 應用程式。可以使用 XML 合併工具合併自定義內容和新的 XML 模式。
以下函式使用 XQuery 的 some 結構。它與 for 迴圈非常相似,但它不會為序列中的每個專案返回輸出,而是在序列中的一個專案滿足某些條件時才返回一個布林值 true 或 false。在本例中,條件是,如果元素名稱的字尾以 text、note 或 description 結尾,我們將使用 textarea。
declare function schema-to-xforms:is-textarea($element-name as xs:string) as xs:boolean {
(: if the element name has any of the following suffix we map it to the input element type :)
let $textarea-suffixes :=
<items>
<item>text</item>
<item>note</item>
<item>description</item>
</items>
let $lower-case-element-name := lower-case($element-name)
return
some $type in $textarea-suffixes/item
satisfies ends-with($lower-case-element-name, $type)
};
為了使我們的 XForms 應用程式能夠在使用者介面中自動放置日曆選擇器,我們需要將每個元素繫結到一個 XML 模式日期型別。
以下是一個日期型別的示例繫結
<xf:model>
...
<xf:bind nodeset="//TaskStartDate" type="xs:date"/>
<xf:bind nodeset="//TaskEndDate" type="xs:date"/>
...
</xf:model>
如果使用適當的命名約定,並將每個元素的字尾都以“Date”結尾,則從 XML 模式中的所有元素生成這些繫結的 XQuery 非常簡單。用於生成所有日期繫結的查詢只是使用 XQuery 函式 ends-with(),例如以下內容
for $element in $schema//xs:element[ends-with(lower-case(@name), 'date')]
return
<xf:bind nodeset="//{string($element/@name)}" type="xs:date"/>
如果將日期儲存在屬性中,則還需要對屬性執行此操作。
以同樣的方式,您也可以查詢所有以“indicator”結尾的字尾的元素,將包含“true”和“false”的輸入控制元件轉換為複選框。
for $element in $schema//xs:element[ends-with(lower-case(@name), 'indicator')]
return
<xf:bind nodeset="//{string($element/@name)}" type="xs:boolean"/>
您可以透過查詢所有不是複雜元素並且不允許出現零次的元素來獲取 XML 模式中所有非可選元素的列表。如果一個元素是複雜的,它將有一個 complexType 的子元素。我們的 XPath 表示式必須透過新增一個包含 not() 函式的謂詞來刪除這些元素:xs:element[not(xs:complexType)。然後,我們必須使用一個布林值 and 語句來排除所有沒有 minOccurs='0' 屬性的元素。
for $element in $schema//xs:element[not(xs:complexType) and not(@minOccurs='0')]
return
<xf:bind nodeset="//{string($element/@name)}" required="true()"/>
您可以使用 group 元素來跟蹤表單中資料的上下文。
例如,如果表單例項具有以下結構
<root>
<sub-node>
<sub-sub-node>
<fname>John</fname>
<lname>Doe</fname>
</sub-sub-node>
</sub-node>
</root>
那麼您將生成以下 xf:group 元素,其 nodeset 屬性設定為正確的上下文
<xf:group nodeset="/root/sub-node/sub-sub-node">
<xf:label class="group-label">contact</xf:label>
<xf:input ref="fname">
<xf:label>Name: </xf:label>
<xf:input>
<xf:input ref="lname">
<xf:label>Name: </xf:label>
<xf:input>
</xf:group>
您還可以使用邊界框對組進行樣式設定,類似於 HTML fieldset 的樣式設定方式。
- HTML to XForms in XSLT 1 約翰·克拉克在 2006 年撰寫的一篇文章,內容是使用 XSLT 將 XML 模式轉換為 XForms。