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。