XForms/Relevant
XForms 还允许您根据实例数据中的某个值有条件地显示表单的一部分。通常,这用于当表单的一个字段的答案有条件地显示表单的另一部分时。
该格式是在 xf:model 中使用 xf:bind 语句。
<xf:model>
<xf:bind nodeset="NodeYowWantToConditionallyDisplay" relevant="XPathExpression"/>
</xf:model>
以下示例演示了这一点。
Relevancy 演示 注意:示例应用程序中的 RelevancySelector.xhtml 不完整。
在以下示例中,第二个输入字段根据第一个实例值的整数值有条件地显示。
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<title>Testing the XForms bind relevant attribute.</title>
<head>
<xf:model>
<xf:instance>
<var xmlns="">
<first>1</first>
<second>This is the second value</second>
</var>
</xf:instance>
<xf:bind nodeset="/var/first" type="xs:decimal" />
<xf:bind nodeset="/var/second" relevant="/var/first > 0" />
</xf:model>
</head>
<body>
<p>Demonstration of relevant fields.</p>
<xf:select1 ref="/var/first" >
<xf:label>Should I show the second question? </xf:label>
<br />
<xf:item select="yes">
<xf:label>Yes Please!</xf:label>
<xf:value>1</xf:value>
</xf:item>
<xf:item>
<xf:label>No Thank You</xf:label>
<xf:value>0</xf:value>
</xf:item>
</xf:select1>
<br />
<xf:input ref="/var/second">
<xf:label>Second value: </xf:label>
</xf:input>
</body>
</html>
有时您会有一系列很多项目,一个项目的显示取决于其他项目的值。谓词是将 AND/OR 操作附加到用作相关性表达式的路径表达式末尾的一种方法。
以下示例使用带两个谓词的 bind。序列中的第二个项目绑定到第一个项目。要做到这一点,您必须在节点集中选择第二个项目 item[2],并在 item[1] 谓词的末尾添加 [. > 2.0]。
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<head>
<xf:model>
<xf:instance id="instanceData">
<data xmlns="">
<item>0.00</item>
<item>0.00</item>
</data>
</xf:instance>
<!-- this rule will only allow the second item to be displayed if the first value is over 2.0 -->
<xf:bind nodeset="instance('instanceData')/item[2]" relevant="instance('instanceData')/item[1][. > 2.0]" />
</xf:model>
</head>
<body>
<xf:input ref="instance('instanceData')/item[1]">
<xf:label>First item: </xf:label>
</xf:input>
<br />
<xf:input ref="instance('instanceData')/item[2]">
<xf:label>Second item: </xf:label>
</xf:input>
</body>
</html>
由于表单的一部分通常是可见的,或者不可见的,所以使用布尔值来确定是否应该显示该字段是很自然的。
在此示例中,如果 InputIndicator 为 true,则第二个输出实例可见。
如果 InputIndicator 为 false,则第二个输出不可见。
请注意,使用了表达式 .='true'
。这是一个字符串比较。理想情况下,您只需能够使用 mynoode=true() 测试节点,但我使用这种方法遇到了问题。
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<title>Example of binding to to boolean controls</title>
</head>
<body>
<xf:model id="model">
<xf:instance id="input">
<DataIn xmlns="">
<InputIndicator>false</InputIndicator>
</DataIn>
</xf:instance>
<!-- make the input data type be a XML Schema type boolean -->
<xf:bind id="input_bind" nodeset="/DataIn/InputIndicator" type="xs:boolean"></xf:bind>
<!-- second instance bound to outputs -->
<xf:instance id="output">
<DataOut xmlns="">
<OutputValue>Hello World!</OutputValue>
</DataOut>
</xf:instance>
<!-- if the input is true, then the output is relevent -->
<xf:bind id="output_bind" nodeset="instance('output')/OutputValue" relevant="instance('input')/InputIndicator[.='true']"/>
</xf:model>
<p>
<xf:input bind="input_bind">
<xf:label>Check to see the value of output: </xf:label>
</xf:input>
<br/>
<xf:output bind="output_bind">
<xf:label>Value of Output: </xf:label>
</xf:output>
</p>
</body>
</html>
在此示例中,使用了一个简单的复选框来有条件地显示一个字段。
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<title>Testing the relevant attribute of the bind element with boolean values.</title>
<xf:model>
<xf:instance>
<var xmlns="">
<first>true</first>
<second/>
</var>
</xf:instance>
<xf:bind nodeset="/var/first" type="xs:boolean" />
<xf:bind nodeset="/var/second" relevant="/var/first='true'" />
</xf:model>
<body>
<p>The input field should only display if the first value is checked.</p>
<xf:input ref="/var/first">
<xf:label>Display the next input?: </xf:label>
</xf:input>
<br />
<xf:input ref="/var/second">
<xf:label>Display this only if the first answer is true: </xf:label>
</xf:input>
</body>
</html>
在此示例中,对布尔值的类型转换没有任何影响,因为 relevant="/var/first=true()" 无法按预期工作。必须使用字符串比较。
此示例显示如何根据 select1 控件的值有条件地显示视图。
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<title>Testing the XForms bind relevant attribute based on a select1 control.</title>
<xf:model>
<xf:instance>
<data xmlns="">
<select1value>1</select1value>
<view1 />
<view2 />
<view3 />
</data>
</xf:instance>
<xf:bind nodeset="/data/select1value" type="xs:decimal" />
<xf:bind nodeset="/data/view1" relevant="/data/select1value = 1" />
<xf:bind nodeset="/data/view2" relevant="/data/select1value = 2" />
<xf:bind nodeset="/data/view3" relevant="/data/select1value = 3" />
</xf:model>
<body>
<p>Demonstration of relevant fields.</p>
<xf:select1 ref="/data/select1value">
<xf:label>What view would you like to see? </xf:label>
<br />
<xf:item select="yes">
<xf:label>View 1</xf:label>
<xf:value>1</xf:value>
</xf:item>
<xf:item>
<xf:label>View 2</xf:label>
<xf:value>2</xf:value>
</xf:item>
<xf:item>
<xf:label>View 3</xf:label>
<xf:value>3</xf:value>
</xf:item>
</xf:select1>
<br />
<xf:input ref="/data/view1">
<xf:label>First view: </xf:label>
</xf:input>
<xf:input ref="/data/view2">
<xf:label>Second view: </xf:label>
</xf:input>
<xf:input ref="/data/view3">
<xf:label>Third view: </xf:label>
</xf:input>
</body>
</html>
请注意,功能类似于 <xf:switch> 和 <xf:case> 组合,但未使用 <xf:toggle>。
以下行是执行实际绑定的行。在将一个实例绑定到另一个实例时,您应该使用 instance() 函数。
还要注意,您必须将 InputIndicator(句点)的文本与 true 进行比较,而不是将 InputIndicator 本身进行比较。
<xf:bind id="output_bind"
nodeset="instance('output')/OutputValue"
relevant="instance('input')/InputIndicator[.='true']" />
有时您需要一种一致的方法来有条件地显示表单中的视图。例如,如果您希望非程序员维护视图显示时的业务逻辑,则可以由外部规则引擎生成绑定到视图的规则。
要使此方法起作用,您需要创建一个用于控制表单视图的中央实例。
<xf:instance id="views" xmlns="">
<data>
<named-view-1/>
<named-view-2/>
<named-view-3/>
</data>
</xf:instance>
我们将此架构称为“命名视图”架构,因为可以利用外部工具来声明任何命名视图的渲染规则。这将是表单中的一个中心位置,它生成视图实例和绑定表达式。
每个视图都包装在一个组元素中,该元素将组绑定到视图中的实例。
<xf:group ref="instance('views')/named-view-1">
<!-- these elements will be conditionally displayed based on the relevancy of named-view-1 -->
</xf:group>
<xf:group ref="instance('views')/named-view-2">
<!-- these elements will be conditionally displayed based on the relevancy of named-view-2 -->
</xf:group>
<xf:group ref="instance('views')/named-view-2">
<!-- these elements will be conditionally displayed based on the relevancy of named-view-3 -->
</xf:group>
然后,每个视图的显示规则可以存储在 bind 语句中。
<xf:bind nodeset="instance('views')/named-view-1" relevant="XPath-expression-that-returns-a-boolean-for named-view-1"/>
<xf:bind nodeset="instance('views')/named-view-2" relevant="XPath-expression-that-returns-a-boolean-for named-view-2"/>
<xf:bind nodeset="instance('views')/named-view-3" relevant="XPath-expression-that-returns-a-boolean-for named-view-3"/>
然后,每个表单都可以有一个“规则文件”,它看起来类似于以下内容。
<form-rules-file>
<form-id>my-form-ver-2</form-id>
<display-rule>
<named-view>named-view-1</named-view>
<xpath-expression>XPath-expression-that-returns-a-boolean-for named-view-1</xpath-expression>
</display-rule>
<display-rule>
<named-view>named-view-2</named-view>
<xpath-expression>XPath-expression-that-returns-a-boolean-for named-view-2</xpath-expression>
</display-rule>
<display-rule>
<named-view>named-view-2</named-view>
<xpath-expression>XPath-expression-that-returns-a-boolean-for named-view-3</xpath-expression>
</display-rule>
</form-rules-file>
然后,您可以构建另一个 XForms 应用程序,允许非程序员维护这些规则文件,以及一个简单的转换,在加载 XForms 模型时将实例和 bind 语句置于 XForms 模型中。可能仍然需要手动将原始组添加到表单中,但添加视图后,可以使用单独的应用程序维护规则。
以下示例,如果国家代码为“usa”,则有条件地显示两个邮政编码字段,或者如果字段不是“usa”,则显示邮政编码。
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<head>
<title>Testing the XForms bind relevant attribute.</title>
<style language="text/css">
<![CDATA[
@namespace xf url("http://www.w3.org/2002/xforms");
/* this allows the descenders (jpqy) to be visible in the drop down list */
xf|select1 .xf-value {height: 1.5em;}
.ZipCode .xf-value {width:5ex}
.ZipCodeSuffix .xf-value {width:4ex}
.PostalCode .xf-value {width:10ex}
]]>
</style>
<xf:model>
<xf:instance xmlns="" id="save-data">
<data>
<CountryCode>usa</CountryCode>
<ZipCode>12345</ZipCode>
<ZipCodeSuffix>1234</ZipCodeSuffix>
<PostalCode>AB-1234</PostalCode>
</data>
</xf:instance>
<!-- The views instance are boolean values that tell what fields are visible -->
<xf:instance xmlns="" id="views">
<data>
<DisplayZipCode/>
<DisplayPostalCode/>
</data>
</xf:instance>
<!-- this rule only displays the zip code if the country code is 'usa'-->
<xf:bind id="DisplayZipCode"
nodeset="instance('views')/DisplayZipCode"
relevant="instance('save-data')/CountryCode='usa'" />
<xf:bind id="DisplayPostalCode"
nodeset="instance('views')/DisplayPostalCode"
relevant="not(instance('save-data')/CountryCode='usa')" />
</xf:model>
</head>
<body>
<p>Demonstration of binding Zip Code Input</p>
<xf:select1 ref="instance('save-data')/CountryCode" selection="open">
<xf:label>Country:</xf:label>
<xf:item>
<xf:label>USA</xf:label>
<xf:value>usa</xf:value>
</xf:item>
<xf:item>
<xf:label>Canada</xf:label>
<xf:value>can</xf:value>
</xf:item>
<xf:item>
<xf:label>Mexico</xf:label>
<xf:value>mex</xf:value>
</xf:item>
<xf:item>
<xf:label>Other</xf:label>
<xf:value>other</xf:value>
</xf:item>
</xf:select1>
<br/>
<xf:group bind="DisplayZipCode">
<xf:input ref="instance('save-data')/ZipCode" class="ZipCode">
<xf:label>Zip Code: </xf:label>
</xf:input>
<xf:input ref="instance('save-data')/ZipCodeSuffix" class="ZipCodeSuffix">
<xf:label>-</xf:label>
</xf:input>
</xf:group>
<xf:input ref="instance('save-data')/LocationPostalID" bind="DisplayPostalCode" class="DisplayPostalCode">
<xf:label>Postal Code: </xf:label>
</xf:input>
</body>
</html>
条件显示最常见的发生之一是重复元素的删除功能。通常,您不希望删除最后一个。请参阅 XForms/Conditional delete 示例。