Re: [xsl] Alternative to except operator that preserves order?

Subject: Re: [xsl] Alternative to except operator that preserves order?
From: TW <zupftom@xxxxxxxxxxxxxx>
Date: Tue, 10 Jan 2012 09:16:56 +0100
2012/1/10 Andrew Welch <andrew.j.welch@xxxxxxxxx>:
> On 10 January 2012 07:23, TW <zupftom@xxxxxxxxxxxxxx> wrote:
>> I'm processing a sorted sequence of elements, recursively eliminating
>> elements that have already been processed.  I'm using "except" for
>> this purpose, but except destroys the order and returns the remaining
>> elements in document order, so I have to re-sort them every time.  Not
>> so much of a problem because the sequences are not very large, but I
>> wondered, whether in general there is a better idiom for preserving
>> the pre-sorted order in situations like this.  The archive didn't make
>> me any wiser.
>
> Small, complete runnable code sample demonstrating the problem please.
>


It's really about the general problem of keeping the order of a
sequence when removing items, not a specific problem.  But here is an
example.  This stylesheet can be applied to itself:


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
    xmlns:xs="http://www.w3.org/2001/XMLSchema";>

  <xsl:template name="dummy">
    <dummy x="a56"/>
    <dummy x="a-3"/>
    <dummy x="d52"/>
    <dummy x="d38"/>
    <dummy x="s21"/>
    <dummy x="b93"/>
    <dummy x="a1"/>
    <dummy x="d6"/>
    <dummy x="s4"/>
    <dummy x="d143"/>
    <dummy x="k89"/>
    <dummy x="s-23"/>
    <dummy x="d-6"/>
  </xsl:template>

  <xsl:template match="/">
    <output>
      <xsl:call-template name="processSequence">
        <xsl:with-param name="elements" select="//dummy" as="element()*"/>
      </xsl:call-template>
    </output>
  </xsl:template>

  <xsl:template name="processSequence">
    <xsl:param name="elements" as="element()*"/>

    <xsl:variable name="elementSubset" as="element()*">
      <xsl:call-template name="selectSomeElements">
        <xsl:with-param name="elements" as="element()*">
          <!-- At this point, the sequence has to be re-sorted every
            time because oder is destroyed by except below -->
          <xsl:perform-sort select="$elements">
            <xsl:sort select="number(substring(@x,2))"/>
          </xsl:perform-sort>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="remainingElements"
        select="$elements except $elementSubset"/>

    <xsl:for-each select="$elementSubset">
      Do something
      <xsl:copy-of select="."/>
    </xsl:for-each>

    <xsl:if test="$remainingElements">
      <xsl:call-template name="processSequence">
        <xsl:with-param name="elements" select="$remainingElements"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="selectSomeElements">
    <xsl:param name="elements" as="element()*"/>

    <!-- Bogus selection criterium,
      more complex recursive template oringially -->
    <xsl:sequence select="$elements[position() = (1,3)]"/>
  </xsl:template>

</xsl:stylesheet>

Current Thread