内容


模型驱动的 XML 表单生成,第 1 部分

从使用 XML Forms Generator 开始

从 XML 实例数据中生成符合标准的表单

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 模型驱动的 XML 表单生成,第 1 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:模型驱动的 XML 表单生成,第 1 部分

敬请期待该系列的后续内容。

表单在当今的软件应用程序中是无处不在,而且它们促进了用户输入,而用户输入正是业务流程的关键所在。由此,表单生成的自动化是非常引人注意,因为实际中任何软件系统的开发都需要创建一个或多个表单来收集用户输入。

表单技术的标准化的、数据驱动的方法有助于构建表单生成技术。表单的标准化格式支持创建好理解的、可移植的表单,而数据驱动的方法使基于所收集的数据表示来生成表单变得更容易,特别是附有描述那些数据特性的元数据的表。

Eclipse 建模框架(Eclipse Modeling Framework,EMF)提供了这些元数据的表示,并将之绑定到真正的实例数据中,同时提供了用来对这些结构进行内省(introspection)的 API 和工具。可以将数据的 EMF 表示当作为实例数据集合生成表单的理想起点。

因此,如果给定要收集数据的描述(例如 XML 文档)以及数据的 EMF 模型,那么几乎立即就可以生成丰富的工作表单。本文描述了用于完成该工作的工具。

本文所展示的解决方案还可用于从 WSDL 文档生成表单。该系列的第 2 部分将介绍此过程。

这里描述的工具是与开放源码的 Eclipse 工具平台无缝集成在一起,可以将它作为 XML Forms Generator,从 IBM alphaWorks 上免费获得。

XForms

万维网联盟(World Wide Web Consortium,W3C)为表单数据的表示和收集开发了 XForms 标准。据 W3C 建议(Recommendation)所描述的,XForms 将成为“下一代 Web 表单”。XForms 提供了许多超过现有 HTML 表单技术的优点。按照建议(Recommendation)本身所声称的,“通过将传统的 XHTML 表单分成 3 个部分:XForms 模型、实例数据和用户界面。它将表示与内容分离,允许重用,并提供强类型(strong typing),这些减少了往返服务器的次数,提供了设备无关性,并降低了对于脚本编制的需要。”

驱动 XForm 的实例数据就是 XML 文档,该文档可由支持数据验证的描述性的 XML Schema 进行支持。该机制非常适合于使用 EMF,EMF 为 XML Schema 文档到 EMF 模型的转换提供了工具,同时也为符合这些模型的 XML 实例文档的序列化(serialization)和反序列化(deserialization)提供了工具。

此外,作为纯 XML,XForms 文档可以受到 EMF 模型的支持,您可以创建并序列化 XForms 文档,该文档被确保符合 EMF 模型。EMF 模型还易于处理跨名称空间的引用,这很重要,因为据 XForms 1.0 建议(Recommendation)中所述,“XForms 不是一种独立的文档类型,而是专门用于集成到其他标记语言中,如 XHTML。”XForms 还使用 XML Events 规范中定义的标记(markup)来驱动 XForms 文档中的事件(eventing),代替 HTML 表单中用于相同目的的更为复杂的脚本编制。

换言之,XForms 文档将总是一种复合文档,如 developerWorks 文章“Model-driven compound document development”中所定义的那样。因此,XML Forms Generator 利用了 Compound XML Document Editor 底层的许多核心技术,其中包括 EMF 的使用、模型的发现和呈现程序就绪(renderer-ready)的序列化。

图 1 中的技术栈说明了 XML Forms Generator 和 Compound XML Document Editor 是如何共享公共基础的。

图 1. 技术栈
技术栈
技术栈

XML Forms Generator

XML Forms Generator Eclipse 插件采用模型驱动的方法来生成表单。作为起始点,它使用 WSDL 文档或具有 EMF 支持模型的 XML 实例文档。所生成的表单符合 XHTML 和 XForms 1.0 标准,并且可以在流行的 XHTML/XForms 呈现程序(renderer)中进行查看。

在从 XML 实例文档生成表单时,XML Forms Generator 可以访问该 XML 实例文档所属的数据域的模型。因此,对于实力文档中的每个数据项,Generator 都自动创建合适的表单构造。那些构造包括类型约束、长度约束、控制类型(下拉列表、文本输入、范围)和迭代结构。

XML Forms Generator 还可以从源 WSDL 文档中生成 XHTML/XForms 文档。其中还包括了用于生成和测试 JavaServer Pages(JSP)Web 服务响应模板的工具(tooling)。

立刻进入工作表单

XML Forms Generator 可以通过少量鼠标单击生成有效的工作表单。与其他的表单创建方法相比,最简单的就是在本文编辑器中手工创建表单。诸如 Compound XML Document Editor 的上下文敏感的编辑器 —— 有一些可以提供提示并保证构造有效文档的上下文敏感的菜单 —— 极大地改进了形式自由的文本编辑,但不提供任何可称为表单生成自动化的东西。

另一种可能的技术通过提供一个编辑器,该编辑器基于描述了表单的未指定实例数据的 XML Schema 的分析填充合适的控件面板,从而提供部分自动化。然而,尽管该模式提供了上下文敏感的、面向数据的、更好的表单构造,但仍然要终端用户负责实际从可获得的构造组织一个表单。

图 2. 从头创建表单的不同方法的难度比较
从头创建表单的不同方法的难度比较
从头创建表单的不同方法的难度比较

相比之下,XML Forms Generator 允许几乎可以立刻创建全功能的表单。通过使用 XML 数据实例作为起始点,Generator 知道所生成的表单必须收集哪些指定数据,从而知道创建哪些表单字段。类似地,当从 WSDL 文档开始时,要对操作进行选择,则允许检查特定的消息部件,以了解必须生成哪些表单输入。

XML Forms Generator 为所生成的表单提供了定制选项的取样,其中包括何时应将输入字段生成为 textarea 控件以接收更多正文输入的设置,以及表单的提交目标。但为了生成全功能的表单,只需要极少的用户输入。在生成并测试这样的表单之后,任何视觉的或其他的修改几乎都可以在开发人员喜欢的编辑器中进行。

通过生成全功能的表单 —— 可以立即进行测试以确保收集并提交合适的数据 —— XML Forms Generator 以其他表单创建方法所无法实现的方式加速了符合标准的表单的开发。

从数据中生成

XForms 需要表单控件可以访问的 XML 实例,因此,实例文档自然就是 XForms 生成的起始点。

此外,XML Forms Generator 受益于 XForms 所鼓励的数据实例创建与预制表单创建之间的关系分离。在典型的开发过程中,数据域专家将创建 XML 实例及其相应的模型,并将它们交付给更关注 UI 的表单开发人员。然后,表单开发人员可以使用 XML Forms Generator 极其快速地从提供的实例数据中生成可测试的工作表单。

这一节演示了 XML Forms Generator 如何使用模型信息从 XML 实例文档中创建表单。

一个简单的表单:邮政地址

以下是一个简单实例,展示了 XML Forms Generator 的一些关键功能。清单 1 是一个相当小的表示了邮政地址的 XML 文档:

清单 1. 邮政地址文档
<PostalAddress type="streetAddress" 
               xmlns="http://ns.hr-xml.org/2004-08-02">
    <CountryCode>US</CountryCode>
    <PostalCode>61043</PostalCode>
    <Region>IL</Region>
    <Municipality>OAKWOOD</Municipality>
    <DeliveryAddress>
        <AddressLine>143 MAIN ST.</AddressLine>
        <AddressLine/>
        <AddressLine/>
    </DeliveryAddress>
</PostalAddress>

清单 2 是该 XML 的模式(Schema):

清单 2. 清单 1 中文档的 XML 模式
<xsd:complexType name="PostalAddressType">
    <xsd:sequence>
        <xsd:element name="CountryCode" type="xsd:string"/>
        <xsd:element name="PostalCode" type="xsd:string"/>
        <xsd:element name="Region" type="xsd:string"
                     maxOccurs="unbounded"/>
        <xsd:element name="Municipality" type="xsd:string"
                     minOccurs="0"/>
        <xsd:element name="DeliveryAddress" minOccurs="0">
            <xsd:complexType>
                <xsd:sequence>
                    <xsd:element name="AddressLine" type="xsd:string"
                                 minOccurs="0" maxOccurs="unbounded"/>
                </xsd:sequence>
            </xsd:complexType>
        </xsd:element>
    </xsd:sequence>
    <xsd:attribute name="type" default="undefined">
        <xsd:simpleType>
            <xsd:restriction base="xsd:string">
                <xsd:enumeration value="postOfficeBoxAddress"/>
                <xsd:enumeration value="streetAddress"/>
                <xsd:enumeration value="militaryAddress"/>
                <xsd:enumeration value="undefined"/>
            <xsd:restriction>
        </xsd:simpleType>
    </xsd:attribute>
</xsd:complexType>
<xsd:element name="PostalAddress" type="PostalAddressType"/>

XML Forms Generator 检查数据实例及其底层模型,以生成合适的 XForms 构造。简言之,该实例文档将决定生成哪些字段,而模型定义将决定这些字段的样式和行为。当前实例包含 XML Forms Generator 将使用的几条提示:

  1. PostalAddress 元素的 type 属性实际上是枚举类型,它允许选择 4 个字符串之一。这种枚举类型是诸如下拉列表等可视表单构造的良好选择,它允许在一个有限的可能选项列表中选择一个选项。
  2. 该实例文档包含多个 AddressLine 元素,AddressLine 元素是 DeliveryAddress 元素的直接后代。这暴露了 DeliveryAddressAddressLine 之间一对多的关系,这种关系在该模式(Schema)的 AddressLine 元素定义中得到了确认,其 maxOccurs 值为 "unbounded"。当存在一对多的关系时,所生成的表单中的可取行为就是展示父元素的所有当前子元素,同时允许添加和删除单个子元素。
  3. 该实例文档仅仅包含一个 Region 元素。因此,只从实例文档来看,无法推断 PostalAddressRegion 之间存在一对多的关系。然而,检查该模式的 Region 定义时,其 maxOccurs"unbounded",您可以看到,PostalAddressRegion 之间实际上存在一对多的关系。

在运行时,模型的真正化身不是 XML Schema;它是基于 XMI 的 EMF ECore 模型定义,其中包含 XML Schema 中给定的相同种类的信息(数据类型、关系基数)。EMF 提供了实用程序来生成来自多种来源的元数据的 ECore 表示,其中包括 XML Schema 和 IBM Rational Rose® 中创建的 UML 类模型。例如,图 3 展示了 IBM Rational Rose 类图中 PostalAddress 元数据的表示:

图 3. PostalAddress 的 Rational Rose 类模型的元数据表示
PostalAddress 的 Rational Rose 类模型的元数据表示
PostalAddress 的 Rational Rose 类模型的元数据表示

当元数据在 ECore 中进行编码并可用于 XML Forms Generator 之后,Generator 就可以基于任何遵循该模型的有效的 XML 实例文档来构造表单了。在 PostalAddress 实例中,结果的 XHTML/XForms 文档通过下列方法来粗略研究上面提到的模型功能:

  1. 通过在所生成的表单中生成下列标记,将用于 PostalAddress 元素的 type 属性的控件作为 XForms select1 控件来进行研究:
    清单 3. XForms select1 控件的标记
    <xforms:select1 ref="/hrxml:PostalAddress/@type"
                    model="model_PostalAddress">
        <xforms:label>Type</xforms:label>
        <xforms:item>
            <xforms:label>Post Office Box Address</xforms:label>
            <xforms:value>postOfficeBoxAddress</xforms:value>
        </xforms:item>
        <xforms:item>
            <xforms:label>Street Address</xforms:label>
            <xforms:value>streetAddress</xforms:value>
        </xforms:item>
        <xforms:item>
            <xforms:label>Military Address</xforms:label>
            <xforms:value>militaryAddress</xforms:value>
        </xforms:item>
        <xforms:item>
            <xforms:label>Undefined</xforms:label>
            <xforms:value>undefined</xforms:value>
        </xforms:item>
    </xforms:select1>
  2. RegionAddressLine 元素生成 XForms repeat 控件,每个元素允许有多个控件。该文档还生成允许插入和删除单个条目的触发器,如下面的生成表单的代码片断所示:
    清单 4. 生成表单的代码片断
    <xforms:repeat model="model_PostalAddress"
                   id="repeat_Region_model_PostalAddress"
                   nodeset="/hrxml:PostalAddress/hrxml:Region">
        <div>
            <xforms:input ref="." model="model_PostalAddress">
                <xforms:label>Region</xforms:label>
            </xforms:input>
        </div>
    </xforms:repeat>
    <xforms:trigger>
        <xforms:label>Add Region</xforms:label>
        <xforms:insert ev:event="DOMActivate"
                       at="index('repeat_Region_model_PostalAddress')"
                       position="after"
                       nodeset="/hrxml:PostalAddress/hrxml:Region"/>
    </xforms:trigger>
    <xforms:trigger>
        <xforms:label>Delete Region</xforms:label>
        <xforms:delete ev:event="DOMActivate"
                       at="index('repeat_Region_model_PostalAddress')"
                       nodeset="/hrxml:PostalAddress/hrxml:Region"/>
    </xforms:trigger>

生成表单中的一些构造,如使用 XHTML div 标签来分隔内容,在 XHTML/XForms 文档中不需要这样做,但是如果由 XML Forms Generator 插入这些标签,则可以提供更清晰的分隔和更多的样式提示。

图 4 展示了所生成的表单在支持 XHTML/XForms 的呈现程序(本例中,X-Smiles 0.93)中的样式。

图 4. 所呈现的生成表单
所呈现的生成表单
所呈现的生成表单

您在这里看到的 PostalAddress 实例是 XML Forms Generator 发行版本提供的众多实例之一。其中还提供了一个支持(backing)模型,因此,一旦安装了 Generator,就可以从那些示例中生成工作表单。

更深入的模型分析

模型中可获得的其他信息也与表单的生成有关。XForms 提供了基于类型约束和包括允许的最小和最大字符串长度等其他属性的验证(实际上,XForms 规范支持基于所有布尔 XPath 表达式的这类验证构造)。此外,通过可从模型中获得的信息,还可以推断出需要其他一些类型的表单控件,例如 XForms range 控件。

类型信息对于 XForms 呈现程序(renderer)特别重要,XForms 呈现程序基于相应实例元素的数据类型或属性呈现不同类型的控件。

XML Forms Generator 检测它所生成的表单字段的元素数据类型和属性。如果发现其类型不同于字符串的原始类型,如 float、double、integer、boolean 或 date,Generator 就会插入一个 XForms bind 元素,以确保表单中该字段的强类型(strong typing)。

呈现程序(renderer)使用类型信息,如 bind 元素中所提供的类型信息,来确定相应表单字段的最佳视觉表示。在图 5 所示的呈现中(在 X-Smiles 0.93 中),三个输入字段都有一个作为其标记源的 XForms input 元素。该呈现程序(renderer)接收每个元素或参考属性的类型信息(本例中,类型分别为 boolean、string 和 date),并呈现合适的控件(在这里,分别是复选框、文本字段和日期选择器)。

图 5. 基于类型信息的 XForms 输入元素的三种不同呈现
基于类型信息的 XForms 输入元素的三种不同呈现
基于类型信息的 XForms 输入元素的三种不同呈现

类型绑定单独向呈现程序(renderer)提供提示,如清单 5 中的标记所示,这导致了图 5 中的呈现:

清单 5. 类型绑定向呈现程序提供了提示
...
<xforms:model id="model_SARSNotificationInformation">
    <xforms:instance id="instance_model_SARSNotificationInformation"
                     src="SARSForm.xml"/>
    <xforms:submission id="submit_model_SARSNotificationInformation"
               action=http://xformstest.org/cgi-bin/showinstance.sh
               method="put"/>
    <xforms:bind nodeset="//cct:Given" type="xsd:boolean"/>
    <xforms:bind nodeset="//cct:StartDate" type="xsd:date"/>
</xforms:model>
...
<xforms:input ref="//cct:Given"
              model="model_SARSNotificationInformation">
    <xforms:label>Given</xforms:label>
</xforms:input>
<xforms:input ref="//cct:Description"
              model="model_SARSNotificationInformation">
    <xforms:label>Description</xforms:label>
</xforms:input>
<xforms:input ref="//cct:StartDate"
              model="model_SARSNotificationInformation">
    <xforms:label>Start Date</xforms:label>
</xforms:input>

同样,您也可以应用约束来表明字符串条目长度的限制。在 XML Schema 中,这些限制将在 minLengthmaxLength 属性中指定。在下面的绑定实例中,最小和最大长度都是 2,以允许 XML Forms Generator 将表达式优化为相等比较:

<xforms:bind nodeset="//cct:Code" constraint="string-length(.)=2"/>

XForms 还允许按照成功提交表单的需求说明特定的元素或属性。XML Forms Generator 检测必要的属性,并添加按照需要标记这些属性的 bind 元素:

<xforms:bind nodeset="//hrxml:Name/@role" required="true()"/>

从模型获得的其他信息可以显示对于 XForms range 控件的需要。在清单 6 中,发现实例元素是数字类型的,其 minValuemaxValue 分别为 0 和 200:

清单 6. XForms range 控件
<xforms:range ref="cct:Age" model="model_SARSNotificationInformation"
              start="0" end="200" step="1">
    <xforms:label>Age</xforms:label>
</xforms:range>
<xforms:output ref="cct:Age"
               model="model_SARSNotificationInformation"/>

最后,模式(Schema)中的枚举类型可能是原始类型的联合(union)的一个组成部分。在这种情况下,理想的数据条目构造将是一个控件,用这个控件,用户可以从枚举中定义的可用值中进行选择,同时保留输入与枚举值可能不相符的自由形式的数据的功能。XForms 以 "open" 选择的形式提供了这样的控件:

<xforms:select1 ref="./@employerOrgType" model="model_Resume"
                selection="open">
...

XML Forms Generator 通过在具有枚举类型的元素或属性上使用定制的 ECore 注释,检测对于 open 选择的需要。这将导致向为枚举类型所生成的 select1 控件添加 selection="open" 属性。

结束语

XML Forms Generator 利用 EMF 中的模型驱动开发(Model Driven Development)的概念来支持从 XML 实例数据中生成表单。Generator 是基于标准的、模型驱动的工具,可用它立即生成工作表单,为表单的开发提供一个良好开端。

WSDL 是为必须收集的数据提供的另一种公共描述机制。第 2 部分将更详细地介绍从 WSDL 文档实现 XML Forms Generator 的表单生成。

致谢:特别感谢 IBM 的 Kelvin Lawrence 和 Henry Tran。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML, Open source
ArticleID=93649
ArticleTitle=模型驱动的 XML 表单生成,第 1 部分: 从使用 XML Forms Generator 开始
publish-date=09082005