|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionOne of my sites allows people to post their short stories, and I'd always been bothered by the fact that when the titles were sorted alphabetically, I would have a long list under T, where all the titles beginning with "The" would congregate. Traditional libraries use a sort order called the grammatic order, where titles are categorized based on the first significant word. In theory, this word could be any one in the title, but in practice nowadays, it'll usually be the first word that isn't an article (i.e. A/An or The). So instead of this plain alphabetical list:
The titles should be sorted as follows:
(In fact, to reduce confusion, the titles could be listed as, for example, "Tale of Two Cities, A", but I'll just concentrate on sorting in this particular article.) When I was looking into methods to achieve this on my web site, I soon discovered that the XSL Customising xsl:sortIn the examples below, I will assume that we are working with an XML source that has the following structure (a complete XML file and the corresponding stylesheet are included in the source zip file): <Stories>
<Story>
<Title>War and Peace</Title>
</Story>
<Story>
<Title>The Bostonians</Title>
</Story>
...
</Stories>
In order to sort these elements by the complete title, you would simply use code like this: <xsl:for-each select="Story">
<xsl:sort select="Title"/>
<xsl:value-of select="Title"/>
</xsl:for-each>
When an However, we actually want some of the titles to be sorted according to the second word, not the first, and in those cases, we need the processor to evaluate the Title string starting with the first space. The <xsl:sort select="substring-after(Title, ' ')"/>
The result of
Unfortunately, while this will indeed put The Bostonians under "B", it will also put War and Peace under "A". What's more, titles which do not contain any spaces end up unsorted at the beginning of the list, because the function doesn't return anything at all in that case, and the processor therefore doesn't include them in the sorted list. We need to be more specific about which titles need to be sorted by their second word. Fortunately, the substring(substring-after(Title, ' '), 0 div starts-with(Title, 'The '))
The second parameter of the In this case, dividing 0 by the boolean value returned by the At this point, we can sort the titles beginning with "The " correctly, so we now need to sort the other titles as well. This is done using a similar substring(Title, 0 div not(starts-with(Title, 'The ')))
In this case, the first parameter is simply Title, since we do want these titles to be sorted by the whole value of the element. The second parameter relies on the same evaluation as above to produce 0 or NaN values depending on whether the title doesn't start with "The ". We now have functions to sort ordinary titles alphabetically and titles starting with The by their second word. The next step is to put them together. Since the two <xsl:sort select="concat(substring(substring-after(Title, ' '),
0 div starts-with(Title, 'The ')),
substring(Title, 0 div not(starts-with(Title, 'The '))))"/>
The result is a list in which the titles are sorted correctly. This functionality can be extended further by simply adding extra criteria to the <xsl:sort select="concat(substring(substring-after(Title, ' '),
0 div boolean(starts-with(Title, 'A ') or starts-with(Title, 'An ')
or starts-with(Title, 'The '))),
substring(Title, 0 div not(starts-with(Title, 'A ')
or starts-with(Title, 'An ') or starts-with(Title, 'The '))))"/>
Points of interestWhile it can be cumbersome and rather verbose at times, the XSL language makes up for it by being incredibly powerful. While designing my website, I was able to achieve things which would have been extremely difficult with just straight ASP and ADO. I hope this example has been a useful introduction to custom sorting. History
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||