<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1"
  xmlns:deltajava="java:com.deltaxml.ext.xslt.saxon.Comparison"
  version="2.0">
  
  <!-- This filter detects and processes contact 'moves'.  A move is defined
    as exactly one added and one deleted contact with the same ID attribute.
    Keys are used to provide efficiency and count adds/deletes.
    We support moves anywhere within the document.  -->
  
  <xsl:key name="deletedContacts" match="contact[@deltaxml:deltaV2='A']" use="@ID"/>
  <xsl:key name="addedContacts" match="contact[@deltaxml:deltaV2='B']" use="@ID"/>
  
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@*, node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="contact[@deltaxml:deltaV2='B']
                              [count(key('deletedContacts', @ID)) eq 1 and count(key('addedContacts', @ID)) eq 1]">
    <xsl:copy>
      <!-- if you don't care about changes to moved contacts you could just apply-templates now,
            otherwise need to re-compare the added/deleted contact using the compare extension function -->
      <xsl:variable name="a" select="key('deletedContacts', @ID)" as="node()"/>
      <xsl:variable name="b" select="." as="node()"/>
      <xsl:variable name="delta" as="node()"
          select="deltajava:compareS9($a, $b, resolve-uri('process-moves.dxp', static-base-uri()))"/>
      <xsl:apply-templates select="$delta/*/@*"/>
      <xsl:comment>This contact element was detected as a move</xsl:comment>
      <xsl:apply-templates select="$delta/*/node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="contact[@deltaxml:deltaV2='A']
                              [count(key('deletedContacts', @ID)) eq 1 and count(key('addedContacts', @ID)) eq 1]">
    <xsl:comment>A contact element with id <xsl:value-of select="@ID"/> was at this location but has been moved</xsl:comment>
  </xsl:template>
</xsl:stylesheet>
