Должен ли я использовать «xxforms: оценивать» в циклах действий, чтобы использовать итератор? - PullRequest
0 голосов
/ 19 января 2012

У меня была проблема с обновлением структуры экземпляра, которая содержит повторяющиеся узлы. Я хотел использовать конструкцию <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 Ответ

1 голос
/ 19 января 2012

Вот версия, которая работает:

<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 не указывает, что аннотации типов на связках должны приводить к вводу типизированного значения (см. Эти примечания к аннотации типа ).Это означает, что в этом случае значение предиката не является числом (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добавлю его.

...