XForms/从文件选择代码
设计表单的人员经常需要维护许多代码表。这些代码表可能会频繁更改,并且可能存在更新集中维护的代码表数据库的流程。因此,您希望每个表单都能动态地从 XML 文件或 RESTful Web 服务获取当前的相关代码。
此示例程序演示了如何直接从文件或代码表 Web 服务读取带有标签的代码列表。在此示例中,包含代码的文件只是一个格式良好的 XML 文件,位于与表单相同的目录中。
以下代码片段通常位于 HTML 头部,演示了如何通过使用实例的“src”属性从与表单相同的目录中的本地文件读取 XML 数据。
<html>
<xf:model>
<xf:instance src="XMLSchemaTypeCode.xml" id="XMLSchemaTypeCode"/>
</xf:model>
</html>
通常会有一个单个 Web 服务来加载所有代码表。此服务可以传递参数,例如代码表的名称以及人员所属的组。这可以缩短长列表的选择列表。
<html>
<xf:model>
<xf:instance id="ApprovalCodes" src="/db/mdr/services/all-codes.xq?code=ApprovalCodes&group=editor"/>
</xf:model>
</html>
将单个代码表加载到单个实例中的问题是,您必须对每个代码表执行单独的 HTTP GET 操作。对于只有一个或两个小选择列表的表单来说,这不是问题。但是,对于具有许多选择列表的大型表单,这会减慢表单响应时间。解决方案是通过单个 HTTP GET 请求将 **所有** 代码加载到单个实例中。然后,可以从该实例中选择每个代码表。
<html>
<xf:model>
<xf:instance id="code-tables" src="/db/mdr/services/all-codes.xq?form=DataElementManager&group=admin"/>
</xf:model>
</html>
在此第二个示例中,整个表单中的所有代码都是由元数据注册表 (MDR) 的服务生成的。此服务器返回的数据是表单中每个 select1 控件的代码集合。
这将在当前目录中查找格式良好的 XML 文件并将其加载到模型实例中。
请注意,在这种情况下,模型被赋予了一个 id。这是必要的,以便允许多个代码表分别读入它们自己的单独模型。
这是程序的屏幕图像。当用户从下拉列表中选择时,输出的值会立即更新。
请注意,屏幕上的标签与模型中存储的标签不同。
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms" >
<head>
<title>Select List From File</title>
/* the default model */
<xf:model>
<xf:instance id="save-data" xmlns="">
<data>
<MyXMLSchemaTypeCode/>
</data>
</xf:instance>
<xf:instance id="code-tables" src="XMLSchemaTypeCode.xml"/>
</xf:model>
</head>
<body>
<p>This selection list was read from a file.</p>
<xf:select1 ref="/MyData/MyXMLSchemaTypeCode">
<xf:label>Select XML Schema data type: </xf:label>
<xf:itemset ref="instance('code-tables')/XMLSchemaTypeCode/item">
<xf:label ref="label"/>
<xf:value ref="value"/>
</xf:itemset>
</xf:select1>
<br/>
<xf:output ref="instance('save-data')/MyXMLSchemaTypeCode">
<xf:label>Value of MyXMLSchemaTypeCode: </xf:label>
</xf:output>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<XMLSchemaTypeCode>
<label>XML Schema Type:</label>
<item>
<label>Date and Time</label>
<value>dateTime</value>
</item>
<item>
<label>Time (HH:MM:SS-06:00)</label>
<value>time</value>
</item>
<item>
<label>Date (yyyy-mm-dd)</label>
<value>date</value>
</item>
<item>
<label>Year and Month</label>
<value>gYearMonth</value>
</item>
<item>
<label>Year (nnnn)</label>
<value>gYear</value>
</item>
<item>
<label>Month and Day</label>
<value>gMonthDay</value>
</item>
<item>
<label>Day of Month (1 .. 31)</label>
<value>gDay</value>
</item>
<item>
<label>Month (1 .. 12)</label>
<value>gMonth</value>
</item>
<item>
<label>String</label>
<value>string</value>
</item>
<item>
<label>Boolean (true/false)</label>
<value>boolean</value>
</item>
<item>
<label>Base 64 Binary</label>
<value>base64Binary</value>
</item>
<item>
<label>Decimal (0.00)</label>
<value>decimal</value>
</item>
<item>
<label>Any URI</label>
<value>anyURI</value>
</item>
<item>
<label>Integer (...,-2,-1,0,1,2,...)</label>
<value>integer</value>
</item>
<item>
<label>Non-Positive Integer (...,-2,-1,0)</label>
<value>nonPositiveInteger</value>
</item>
<item>
<label>Negative Integer (...,-2,-1)</label>
<value>negativeInteger</value>
</item>
<item>
<label>Long (-9,223,372T .. 9,223,372T)</label>
<value>long</value>
</item>
<item>
<label>Int (-2,147,483,648 .. 2,147,483,647)</label>
<value>int</value>
</item>
<item>
<label>Short (-32,768 .. 32,767)</label>
<value>short</value>
</item>
<item>
<label>Byte (-128 .. 127)</label>
<value>byte</value>
</item>
<item>
<label>Non-negative Integer (0..N)</label>
<value>nonNegativeInteger</value>
</item>
<item>
<label>Positive Integer (1..N)</label>
<value>positiveInteger</value>
</item>
<item>
<label>Unsigned Long (0 .. 18,446,744T)</label>
<value>unsignedLong</value>
</item>
<item>
<label>Unsigned Int (0 .. 4,294,967,295)</label>
<value>unsignedInt</value>
</item>
<item>
<label>Unsigned Short (0.. 65,535)</label>
<value>unsignedShort</value>
</item>
<item>
<label>Unsigned Byte (0..255)</label>
<value>unsignedByte</value>
</item>
</XMLSchemaTypeCode>
请注意,为了格式良好,XML 文件 **必须** 包含一个根数据元素,该元素必须与节点集参数匹配。
您可以将实例 **src** 属性替换为指向 XML REST Web 服务的直接路径。例如,如果您将所有代码表放入项目资源集合中,则路径将如下所示
<xf:instance src="../resources/code-tables/PersonGenderCode.xml"/>
或者,如果您的系统代码存储在一个单个 XML 文件中,并且您有一个包装器 XQuery
<xf:instance src="../resources/code-tables/get-codes-for.xq?element=PersonGenderCode"/>
为了保持表单速度,通常最好对所有代码执行一次 HTTP GET 操作。如果每个列表都执行单独的 HTTP GET 操作,则具有许多选择列表的表单加载时间会很长。对于大型表单,表单加载时间很容易提高 10 倍。
以下是加载到单个实例中的所有代码的示例结构
<xf:instance id="code-tables">
<code-tables>
<code-table>
<code-table-name>MyElementCode</code-table-name>
<items>
<item>
<label>Joe Smith</label>
<value>42</value>
</item>
<item>
<label>Sue Johnson</label>
<value>47</value>
</item>
<items>
</code-table>
<code-table>
<code-table-name>ColorCode</code-table-name>
<items>
<item>
<label>Red</label>
<value>1</value>
</item>
<item>
<label>Orange</label>
<value>2</value>
</item>
<items>
</code-table>
</code-tables>
</xf:instance>
将数据加载到模型后,每个 **select1** 或 **select** 控件都可以使用 **xf:itemset** 元素直接从模型获取其数据。Itemset 的工作原理与 repeat 相同,并使用 nodeset(而不是 ref)来获取所有值。以下是如何从代码表实例中获取 itemset 数据的示例。
<xf:select1 ref="instance('save-data')/MyElementName">
<xf:label>My Element:</xf:label>
<xf:itemset nodeset="instance('code-tables')/code-table[code-table-name='MyElementCode']/items/item">
<xf:label ref="label"/>
<xf:value ref="value"/>
</xf:itemset>
</xf:select1>
请注意,谓词 [code-table-name='MyElementCode'] 仅将该代码的项目放入选择列表中。
由于 XML Schema 不包含用于表示的信息,因此我们使用以下工作流作为“最佳实践”。
- 将所有标签/值对存储在外部代码表文件中,或从 Web 服务获取此信息。
- 对于每个表单,创建一个 Web 服务,该服务将为该表单中使用的所有代码生成一个 code-tables 元素。
- 将 code-tables 元素加载到模型中的单独实例中,其 id 为“code-tables”。
- 对于每个 select1 或 select 元素,通过获取具有该名称的代码表,从该实例中选择代码表。
当一组共享通用代码的复杂表单需要放置在它们自己的目录中,但仍然需要链接到代码的中央目录时,您也可以使用相对代码表链接。例如,一个兄弟目录可以称为“code-tables”,并且 src="MyCode.xml" 语句可以修改为 src="../code-tables/MyCode.xml"。
如果您有表单的 XML 模式,您还可以提取每个 simpleType 的所有枚举列表。然后,此代码列表可以传递给一个 Web 服务,该服务会创建注册表中所有代码的列表。这允许表单在 XML 模式中添加新代码时自动更新。
如果您有一个包含表单所有代码的 RESTful Web 服务,您可以用这个 Web 服务 URI 替换 XML 文件。