M
Mark Ritchie
I'm trying to sort and filter some xml using XSLT, sorting the data has been
easy, but filtering it while maintaining the sort order has turned out to be
a lot harder.
Here is an example of the XML
<People>
<Person DisplayName="George Smith" Priority="3">
<Names>
<Name Type="Initials" TypePriority="100" LastUpdated="21/01/2001"
Exclusive="False" FullName="Gq" />
<Name Type="Registered" TypePriority="20" LastUpdated="21/01/1999"
Exclusive="True" FullName="George Smith"/>
</Names>
</Person>
<Person DisplayName="George Quinn" Priority="5">
<Names>
<Name Type="Initials" TypePriority="100" LastUpdated="21/01/2007"
Exclusive="False" FullName="Gq" />
<Name Type="Registered" TypePriority="20" LastUpdated="21/01/2004"
Exclusive="True" FullName="George Quinn"/>
<Name Type="Previous" TypePriority="120" LastUpdated="21/01/2000"
Exclusive="False" FullName="George Smith" />
</Names>
</Person>
<Person DisplayName="George Quinn" Priority="5">
<Names>
<Name Type="Initials" TypePriority="100" LastUpdated="21/01/2007"
Exclusive="False" FullName="Gq" />
<Name Type="Registered" TypePriority="20" LastUpdated="21/01/2004"
Exclusive="True" FullName="George Quinn"/>
<Name Type="Previous" TypePriority="120" LastUpdated="21/01/2000"
Exclusive="False" FullName="George Smith" />
</Names>
</Person>
<Person DisplayName="George Quinn" Priority="1">
<Names>
<Name Type="Initials" TypePriority="100" LastUpdated="21/01/2001"
Exclusive="False" FullName="Gq"/>
<Name Type="Registered" TypePriority="20" LastUpdated="21/01/2002"
Exclusive="True" FullName="George Quinn"/>
<Name Type="Previous" TypePriority="120" LastUpdated="21/01/2000"
Exclusive="False" FullName="George Smyth" />
</Names>
</Person>
</People>
Here is the current XML:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xslutput method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<Person>
<Names>
<xsl:apply-templates select="//Names/Name">
<xsl:sort select="@TypePriority" order="ascending" data-type="number"/>
<xsl:sort select="@LastUpdated" order="descending" />
</xsl:apply-templates>
</Names>
</Person>
</xsl:template>
<xsl:template match="Name">
<Name>
<xsl:copy-of select="@*"/>
</Name>
</xsl:template>
</xsl:stylesheet>
and here's the desired output:
<Person>
<Names>
<Name Type="Registered" TypePriority="20" LastUpdated="21/01/2004"
Exclusive="True" FullName="George Quinn"/>
<Name Type="Initials" TypePriority="100" LastUpdated="21/01/2007"
Exclusive="False" FullName="Gq"/>
<Name Type="Previous" TypePriority="120" LastUpdated="21/01/2000"
Exclusive="False" FullName="George Smith"/>
<Name Type="Previous" TypePriority="120" LastUpdated="21/01/2000"
Exclusive="False" FullName="George Smyth"/>
</Names>
</Person>
The filtering logic is that you can only have one entry for any type that
has an type that is exclusive, but can have as many non exclusive names as
you wish.
Therefore a person can only have one registered name, but can have as many
previous names as they wish.
easy, but filtering it while maintaining the sort order has turned out to be
a lot harder.
Here is an example of the XML
<People>
<Person DisplayName="George Smith" Priority="3">
<Names>
<Name Type="Initials" TypePriority="100" LastUpdated="21/01/2001"
Exclusive="False" FullName="Gq" />
<Name Type="Registered" TypePriority="20" LastUpdated="21/01/1999"
Exclusive="True" FullName="George Smith"/>
</Names>
</Person>
<Person DisplayName="George Quinn" Priority="5">
<Names>
<Name Type="Initials" TypePriority="100" LastUpdated="21/01/2007"
Exclusive="False" FullName="Gq" />
<Name Type="Registered" TypePriority="20" LastUpdated="21/01/2004"
Exclusive="True" FullName="George Quinn"/>
<Name Type="Previous" TypePriority="120" LastUpdated="21/01/2000"
Exclusive="False" FullName="George Smith" />
</Names>
</Person>
<Person DisplayName="George Quinn" Priority="5">
<Names>
<Name Type="Initials" TypePriority="100" LastUpdated="21/01/2007"
Exclusive="False" FullName="Gq" />
<Name Type="Registered" TypePriority="20" LastUpdated="21/01/2004"
Exclusive="True" FullName="George Quinn"/>
<Name Type="Previous" TypePriority="120" LastUpdated="21/01/2000"
Exclusive="False" FullName="George Smith" />
</Names>
</Person>
<Person DisplayName="George Quinn" Priority="1">
<Names>
<Name Type="Initials" TypePriority="100" LastUpdated="21/01/2001"
Exclusive="False" FullName="Gq"/>
<Name Type="Registered" TypePriority="20" LastUpdated="21/01/2002"
Exclusive="True" FullName="George Quinn"/>
<Name Type="Previous" TypePriority="120" LastUpdated="21/01/2000"
Exclusive="False" FullName="George Smyth" />
</Names>
</Person>
</People>
Here is the current XML:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xslutput method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<Person>
<Names>
<xsl:apply-templates select="//Names/Name">
<xsl:sort select="@TypePriority" order="ascending" data-type="number"/>
<xsl:sort select="@LastUpdated" order="descending" />
</xsl:apply-templates>
</Names>
</Person>
</xsl:template>
<xsl:template match="Name">
<Name>
<xsl:copy-of select="@*"/>
</Name>
</xsl:template>
</xsl:stylesheet>
and here's the desired output:
<Person>
<Names>
<Name Type="Registered" TypePriority="20" LastUpdated="21/01/2004"
Exclusive="True" FullName="George Quinn"/>
<Name Type="Initials" TypePriority="100" LastUpdated="21/01/2007"
Exclusive="False" FullName="Gq"/>
<Name Type="Previous" TypePriority="120" LastUpdated="21/01/2000"
Exclusive="False" FullName="George Smith"/>
<Name Type="Previous" TypePriority="120" LastUpdated="21/01/2000"
Exclusive="False" FullName="George Smyth"/>
</Names>
</Person>
The filtering logic is that you can only have one entry for any type that
has an type that is exclusive, but can have as many non exclusive names as
you wish.
Therefore a person can only have one registered name, but can have as many
previous names as they wish.