Search code examples
xformsxsltforms

XForms move node up or down in the XML tree


I need to allow my XForms (using XSLTForms) users move elements up and down the XML tree. I have this working as long as I am using the full path to the element including the instance. However I'm wondering if it is possible to have the same function without referring to the full path or the instance as I am using a series of nested subforms within repeats.

Simplified example bellow: up1 works as expected, up2 does not. The only difference is the path.

<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">
    <head>
        <title>Move Test</title>
        <xf:model>
            <xf:instance id="i-rec">
                <TEI xmlns="http://www.tei-c.org/ns/1.0">
                    <msPart>
                        <msIdentifier>
                            <idno>1</idno>
                            <idno>2</idno>
                            <idno>3</idno>
                            <idno>4</idno>
                        </msIdentifier>
                    </msPart>
                </TEI>
            </xf:instance>
            <xf:instance id="i-move">
                <data xmlns="">
                    <tmp/>
                </data>
            </xf:instance>
        </xf:model>
    </head>
    <body style="margin:3em; padding-left:4em;">
        <h1>Move Test</h1>
        <xf:group ref="instance('i-rec')//*:msPart[1]">
            <xf:group ref="*:msIdentifier"> 
                <xf:repeat id="msIdentifierRepeatLevel1" ref="./*">
                    <xf:trigger appearance="minimal">
                        <xf:label>up1 </xf:label>
                        <xf:action ev:event="DOMActivate">
                            <xf:setvalue ref="instance('i-move')/tmp" value="index('msIdentifierRepeatLevel1')"></xf:setvalue>
                            <xf:insert  
                                nodeset="instance('i-rec')//descendant::*:msPart/*:msIdentifier/*"
                                at="index('msIdentifierRepeatLevel1') - 1" 
                                origin="instance('i-rec')//descendant::*:msPart/*:msIdentifier/*[index('msIdentifierRepeatLevel1')]"
                                position="before"/>
                            <xf:delete nodeset="instance('i-rec')//descendant::*:msPart/*:msIdentifier/*[instance('i-move')/tmp + 1]"/>
                        </xf:action>
                    </xf:trigger> |
                    <xf:trigger appearance="minimal">
                        <xf:label>up2 </xf:label>
                        <xf:action ev:event="DOMActivate">
                            <xf:setvalue ref="instance('i-move')/tmp" value="index('msIdentifierRepeatLevel1')"></xf:setvalue>
                            <xf:insert  
                                nodeset="."
                                at="index('msIdentifierRepeatLevel1') - 1" 
                                origin=".[index('msIdentifierRepeatLevel1')]"
                                position="before"/>
                            <xf:delete nodeset=".[instance('i-move')/tmp + 1]"/>
                        </xf:action>
                    </xf:trigger> 
                    <div><xf:input ref="."/></div>
                </xf:repeat> 
            </xf:group>
        </xf:group>
    </body>
</html>


Solution

  • For "up2" to work as "up1", you should replace "." with "../*"