For tiden jobber jeg en del med CMS-verktøyet Umbraco, som vi har valgt å bruke som grunnlag for publiseringsløsningene vi leverer for mindre kunder. Umbraco er stort sett et glimrende verktøy som dekker de fleste behov innen publisering, og ved hjelp av XSLT kan man langt på vei utvikle den funksjonaliteten man trenger uten å måtte ty til eksterne verktøy. En ting som jeg til å begynne med hadde vanskeligheter med å få til, var sortering av noder i innholdstreet. Dersom sorteringskriteriene er faste, gjør man bare en <xsl:sort select=”whatever” /> inne i <xsl:for-each>, men jeg ville la brukeren velge hvilken sorteringsrekkefølge som skulle brukes. Dette var ikke enkelt å finne dokumentert noe sted, men jeg kom til slutt opp med en løsning.

For hver dokumenttype som skal tillate sorterbare undernoder, legger jeg inn en property med alias “sortField” og type “Sort order selector”. Sistnevnte er en egendefinert datatype som gir en dropdown-meny med menyvalgene “Name”, “Published” og “Index”. Her kan brukeren velge om undernodene skal sorteres alfabetisk (etter nodenavn), kronologisk (etter publiseringstidspunkt) eller manuelt (etter indeks). I tillegg legger jeg inn en property med alias “descending” og type “True/false” (altså en avkrysningsboks). Denne lar brukeren velge å “snu” sorteringsrekkefølgen motsatt vei. Dette kan f.eks. være nyttig for publisering av nyheter, som man ofte vil ha i omvendt kronologisk rekkefølge (nyeste først).

For å muliggjøre manuell sortering (indeks-basert) legger jeg inn en property med alias “sortIndex” og type “Numeric” for hver sorterbare dokumenttype. Dersom brukeren ønsker manuell sortering, er det denne verdien som avgjør rekkefølgen. Noden med lavest indeks havner først (eller sist, dersom “descending” er valgt).

Dette var den enkle biten. Utfordringen ligger i å skrive XSLT-koden som skal utføre sorteringen. Det viser seg nemlig at <xsl:sort> ikke kan ha en variabel som verdi i select-attributtet, og vi kan ikke putte <xsl:sort> inni en <xsl:choose>. Så hva gjør vi? Jo, vi kjører flere betingede sorteringer!

Først litt kode for å avgjøre hvorvidt vi ønsker å sortere i stigende eller synkende rekkefølge. <xsl:sort> kan ha en variabel i order-attributtet, så vi definerer en:

<xsl:variable name="order">
  <xsl:choose>
    <xsl:when test="string($currentPage/descending) = '1'">
      <xsl:text>descending</xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>ascending</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>

Og nå til selve sorteringen og listingen av nodene:

<ul>
<xsl:for-each select="$currentPage/* [@isDoc and string(umbracoNaviHide) != '1']">
  <xsl:sort select="@nodeName[$currentPage/sortField = 'Name']" data-type="text" order="{$order}"/> <xsl:sort select="@createDate[$currentPage/sortField = 'Published']" data-type="text" order="{$order}"/> <xsl:sort select="sortIndex[$currentPage/sortField = 'Index']" data-type="number" order="{$order}"/>
  <li>
    <a href="{umbraco.library:NiceUrl(@id)}">
      <xsl:value-of select="@nodeName"/>
    </a>
  </li>
</xsl:for-each>
</ul>

Som vi ser, har vi tre sorteringer som hver avhenger av verdien i “sortField”. Jeg vet ikke om dette er den mest effektive eller mest elegante løsningen, men den fungerer i alle fall i alle tilfeller jeg har testet.