You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XSLTForms中重复组内元素上下移动功能异常问题求助

解决XSLTForms中跨重复组的元素移动问题

用XSLTForms渲染XForms表单时,把同一可重复父元素<msIdentifier>下的元素分成两个重复组展示(满足UI需求):第一组是country/settlement/institution,第二组是altIdentifier/msName。目前第一组元素能正常在组内上下移动,但第二组完全无法实现移动功能。核心问题是repeat的index只作用于当前分组后的重复组,没法拿到元素在整个父元素里的真实位置,导致移动逻辑里的节点定位完全错误。

可行解决思路

  • 放弃依赖repeat index,计算元素绝对位置:用count(preceding-sibling::*) + 1替代index('xxx'),直接获取当前元素在父节点所有子元素中的真实位置,不受分组影响。
  • 统一基于父元素全量子节点操作:insert和delete操作时,直接定位到父元素的所有子节点集合,用绝对位置确定插入点和删除节点,避免分组repeat的索引干扰。
  • 简化上下文引用:利用XForms的上下文特性,用..直接指代当前元素的父节点<msIdentifier>,不用额外的repeatIndex实例定位父元素,减少冗余。

修改后的完整代码

<html xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:ev="http://www.w3.org/2001/xml-events"
   xmlns:xf="http://www.w3.org/2002/xforms"
   xmlns:tei="http://www.tei-c.org/ns/1.0">
   <head>
      <xf:model id="m-mss">
         <xf:instance id="i-rec">
            <TEI xmlns="http://www.tei-c.org/ns/1.0">
               <msIdentifier>
                  <!-- group a -->
                  <country>1a</country>
                  <institution>2a</institution>
                  <settlement>3a</settlement>
                  <institution>4a</institution>
                  <!-- group b -->
                  <altIdentifier>1b</altIdentifier>
                  <altIdentifier>2b</altIdentifier>
                  <altIdentifier>3b</altIdentifier>
                  <msName>4b</msName>
               </msIdentifier>
            </TEI>
         </xf:instance>
         <xf:instance id="i-move">
            <data xmlns="">
               <tmp/>
            </data>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <h2>Parent Element </h2>
      <xf:repeat ref="instance('i-rec')//tei:msIdentifier" id="msIdentifierRepeatLevel1">
         <div id="elementGroup" style="margin:12px; padding:12px; border:1px solid #ccc;">
            <div>
               <h2>location, institution, settlement</h2>
               <div>
                  <xf:repeat id="msIdentifierRepeatLevel11"
                     ref="./*[contains(local-name(),'country') or contains(local-name(),'settlement') or contains(local-name(),'institution')]">
                     <div class="btn-group" role="group">
                        <xf:trigger appearance="minimal" class="btn controls moveUp inline">
                           <xf:label>up</xf:label>
                           <xf:action ev:event="DOMActivate">
                              <!-- 获取当前元素在父节点中的绝对位置 -->
                              <setvalue ref="instance('i-move')/tmp" value="count(preceding-sibling::*) + 1"/>
                              <xf:if test="instance('i-move')/tmp > 1">
                                 <insert
                                    origin="."
                                    nodeset="../*"
                                    at="instance('i-move')/tmp - 1" position="before"/>
                                 <delete nodeset="../*[instance('i-move')/tmp + 1]"/>
                              </xf:if>
                           </xf:action>
                        </xf:trigger> | <xf:trigger appearance="minimal" class="btn controls moveDown inline">
                           <xf:label>down</xf:label>
                           <xf:action ev:event="DOMActivate">
                              <setvalue ref="instance('i-move')/tmp" value="count(preceding-sibling::*) + 1"/>
                              <xf:if test="instance('i-move')/tmp < count(../*)">
                                 <insert
                                    origin="."
                                    nodeset="../*"
                                    at="instance('i-move')/tmp + 1" position="after"/>
                                 <delete nodeset="."/>
                              </xf:if>
                           </xf:action>
                        </xf:trigger> | <span class="elementLabel"><xf:output value="local-name()" class="elementLabel"/></span>
                     </div>
                     <span class="element">
                        <xf:input class="elementInput" ref="."/>
                     </span>
                  </xf:repeat>
               </div>
            </div>
         </div>
         <div id="elementGroup2" style="margin:12px; padding:12px; border:1px solid #ccc;">
            <div>
               <h2>altIdentifier, msName</h2>
               <div>
                  <xf:repeat id="msIdentifierRepeatLevel12"
                     ref="./*[contains(local-name(),'altIdentifier') or contains(local-name(),'msName')]">
                     <div class="btn-group" role="group">
                        <xf:trigger appearance="minimal" class="btn controls moveUp inline">
                           <xf:label>up</xf:label>
                           <xf:action ev:event="DOMActivate">
                              <setvalue ref="instance('i-move')/tmp" value="count(preceding-sibling::*) + 1"/>
                              <xf:if test="instance('i-move')/tmp > 1">
                                 <insert
                                    origin="."
                                    nodeset="../*"
                                    at="instance('i-move')/tmp - 1" position="before"/>
                                 <delete nodeset="../*[instance('i-move')/tmp + 1]"/>
                              </xf:if>
                           </xf:action>
                        </xf:trigger> | <xf:trigger appearance="minimal" class="btn controls moveDown inline">
                           <xf:label>down</xf:label>
                           <xf:action ev:event="DOMActivate">
                              <setvalue ref="instance('i-move')/tmp" value="count(preceding-sibling::*) + 1"/>
                              <xf:if test="instance('i-move')/tmp < count(../*)">
                                 <insert
                                    origin="."
                                    nodeset="../*"
                                    at="instance('i-move')/tmp + 1" position="after"/>
                                 <delete nodeset="."/>
                              </xf:if>
                           </xf:action>
                        </xf:trigger> | <span class="elementLabel"><xf:output value="local-name()" class="elementLabel"/></span>
                     </div>
                     <span class="element">
                        <xf:input class="elementInput" ref="."/>
                     </span>
                  </xf:repeat>
               </div>
            </div>
         </div>
      </xf:repeat>
   </body>
</html>

关键修改点说明

  1. 添加tei命名空间:在根元素声明xmlns:tei="http://www.tei-c.org/ns/1.0",避免节点定位时的命名空间问题。
  2. 替换位置计算方式:用count(preceding-sibling::*) + 1获取元素在父节点的真实位置,替代原有的index('xxx')。
  3. 简化父节点引用:用../*直接指代<msIdentifier>下的所有子元素,不用通过repeatIndex实例定位。
  4. 添加边界判断:用<xf:if>限制移动操作仅在元素不在边界时执行,避免无效操作。

内容的提问来源于stack exchange,提问作者wsalesky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 22:01:01