我是否必须在action-loops中使用“xxforms:evaluate”来使用迭代器?

时间:2012-01-19 11:42:46

标签: orbeon xforms

我在更新包含重复节点的实例结构时遇到了问题。我想使用<action while=""/>构造,但在此循环中使用已定义的迭代器时出现问题。最终它总是使用一个值(第一个),即使它是递增的。我使用xxforms:evaluate函数解决了这个问题,因此我有:

xxforms:evaluate(concat('instance(''main'')/item[',xxforms:bind('idx'),']'))

而不是更简单

instance('main')/item[xxforms:bind('idx')]

这是迭代操作中节点列表的唯一方法吗?

示例:

<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:xsd="http://www.w3.org/2001/XMLSchema"
      xmlns:xxforms="http://orbeon.org/oxf/xml/xforms">
  <head>
    <title>Test</title>
    <xf:model id="model">
      <xf:instance id="main" xmlns="">
        <main>
          <item>
            <name />
          </item>
          <item>
            <name />
          </item>
          <item>
            <name />
          </item>
        </main>
      </xf:instance>
      <xf:instance id="temp" xmlns="">
        <main>
          <idx></idx>
          <value>inserted node</value>
        </main>
      </xf:instance>

      <xf:bind id="idx" nodeset="instance('temp')/idx" type="xsd:integer" />
    </xf:model>
  </head>

   <body>
    <xf:trigger>
      <xf:label>Not working as expected</xf:label>
      <xf:action ev:event="DOMActivate">
        <xf:setvalue bind="idx" value="1" />
        <xf:action while="number(xxforms:bind('idx')) le count(instance('main')/item)">
          <xf:insert context="instance('main')/item[xxforms:bind('idx')]" nodeset="name" position="after" origin="instance('temp')/value" if="not(exists(value))" />
          <xf:setvalue bind="idx" value=". + 1" />
        </xf:action>
      </xf:action>
    </xf:trigger>

    <xf:trigger>
      <xf:label>Working as expected but too complicated</xf:label>
      <xf:action ev:event="DOMActivate">
        <xf:setvalue bind="idx" value="1" />
        <xf:action while="number(xxforms:bind('idx')) le count(instance('main')/item)">
          <xf:insert context="xxforms:evaluate(concat('instance(''main'')/item[',xxforms:bind('idx'),']'))" nodeset="name" position="after" origin="instance('temp')/value" if="not(exists(value))" />
          <xf:setvalue bind="idx" value=". + 1" />
        </xf:action>
      </xf:action>
    </xf:trigger>
    <widget:xforms-instance-inspector id="orbeon-xforms-inspector" xmlns:widget="http://orbeon.org/oxf/xml/widget" />
   </body>
</html>

所以我得到了结果(第一次触发):

<main>
  <item>
    <name/>
    <value>inserted node</value>
  </item>
  <item>
    <name/>
  </item>
  <item>
    <name/>
  </item>
</main>

但预期(第二次触发):

<main>
  <item>
    <name/>
    <value>inserted node</value>
  </item>
  <item>
    <name/>
    <value>inserted node</value>
  </item>
  <item>
    <name/>
    <value>inserted node</value>
  </item>
</main>

1 个答案:

答案 0 :(得分:1)

这是一个有效的版本:

<xf:action ev:event="DOMActivate">
    <xf:setvalue bind="idx" value="1"/>
    <xf:action while="xs:integer(xxforms:bind('idx')) le count(instance('main')/item)">
        <xf:insert context="instance('main')/item[xs:integer(xxforms:bind('idx'))]" nodeset="name" position="after"
                   origin="instance('temp')/value" if="not(exists(value))"/>
        <xf:setvalue bind="idx" value=". + 1"/>
    </xf:action>
</xf:action>

问题是xxforms:bind('idx')会返回无类型值,即使您指定了xsd:integer也是如此。 XForms目前没有指定绑定上的类型注释必须提供类型值(请参阅这些notes on type annotation)。这意味着在这种情况下,谓词值不是数字(XPath同时具有布尔值和数字谓词,这通常是混淆的来源)。为了使它成为数字谓词,需要转换为数字。

此处我使用xs:integer,因为number是一种XPath 1遗留函数,它返回xs:double,而count()函数返回xs:integer )。

xxforms:iterate有更简单的解决方案:

<xf:action ev:event="DOMActivate" xxforms:iterate="item">
    <xf:insert if="not(exists(value))"
               context="."
               nodeset="name"
               origin="instance('temp')/value"/>
</xf:action>

iterate目前是一个扩展程序,但是XForms 2 will add it.