xmlsortingxslttimecodes

Sorting timecodes in XLST


Anyone have a thought on how I could sort this? I'm wanting to sort by ascending timecode values in my xlst, but I don't think a typical sort will read the timecode values correctly.

My ultimate goal is to 1) Sort the nodes by timecode values ascending 2) Select the timecode value of the first iteration of the respective color, then the second, then the third, etc.

Please let me know if I need to clarify more.

Here's the XML:

<Metadata>
   <Locator>
   <Label>OUT</Label>
   <Color>Blue</Color>
   <Timecode>00;13;28;26</Timecode>
   <Username>bpayne</Username>
   <Track>V1</Track>
</Locator>
   <Locator>
   <Label>OUT</Label>
   <Color>Magenta</Color>
   <Timecode>00;15;29;26</Timecode>
   <Username>bpayne</Username>
   <Track>V1</Track>
   </Locator>
<Locator>
   <Label>IN</Label>
   <Color>Magenta</Color>
   <Timecode>00;23;48;19</Timecode>
   <Username>bpayne</Username>
   <Track>V1</Track>
</Locator>
<Locator>
   <Label>IN</Label>
   <Color>Magenta</Color>
   <Timecode>00;03;15;13</Timecode>
   <Username>bpayne</Username>
   <Track>V1</Track>
</Locator>
<Locator>
   <Label>OUT</Label>
   <Color>Magenta</Color>
   <Timecode>00;19;50;25</Timecode>
   <Username>bpayne</Username>
   <Track>V1</Track>
</Locator>
<Locator>
   <Label>IN</Label>
   <Color>Magenta</Color>
   <Timecode>00;25;58;05</Timecode>
   <Username>bpayne</Username>
   <Track>V1</Track>
</Locator>
<Locator>
   <Label>IN</Label>
   <Color>Magenta</Color>
   <Timecode>00;07;44;29</Timecode>
   <Username>bpayne</Username>
   <Track>V1</Track>
</Locator>
<Locator>
   <Label>OUT</Label>
   <Color>Magenta</Color>
   <Timecode>00;09;05;28</Timecode>
   <Username>bpayne</Username>
   <Track>V1</Track>
</Locator>
<Locator>
   <Label>IN</Label>
   <Color>Blue</Color>
   <Timecode>00;02;19;23</Timecode>
   <Username>bpayne</Username>
   <Track>V1</Track>
</Locator>
<Locator>
<Label>OUT</Label>
   <Color>Magenta</Color>
   <Timecode>00;13;16;11</Timecode>
   <Username>bpayne</Username>
   <Track>V1</Track>
</Locator>
<Locator>
    <Label>OUT</Label>
    <Color>Blue</Color>
    <Timecode>00;02;31;23</Timecode>
    <Username>bpayne</Username>
    <Track>V1</Track>
</Locator>

And here's a portion of the XLST I'm using. I'm needing to first sort the nodes by timecode value and then transform it with this XSLT:

    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:template match="/">
        <TimeCodes>
            <G1_TC_1_IN>
                <xsl:choose>
                    <xsl:when test="Metadata/Locator[Color = 'Magenta'][1]">
                        <xsl:value-of select="concat(
                        substring-before(Metadata/Locator[Color = 'Magenta'][1]/Timecode, ';'), ':',
                        substring-before(substring-after(Metadata/Locator[Color = 'Magenta'][1]/Timecode, ';'), ';'), ':',
                        substring-after(substring-after(Metadata/Locator[Color = 'Magenta'][1]/Timecode, ';'), ';')
                        )"/>
                    </xsl:when>       
                    <xsl:otherwise>18:00:00;00</xsl:otherwise>
                </xsl:choose>
                <xsl:text>@29.97</xsl:text>
            </G1_TC_1_IN>
            <G1_TC_1_OUT>
                <xsl:choose>
                    <xsl:when test="Metadata/Locator[Color = 'Magenta'][2]">
                        <xsl:value-of select="concat(
                            substring-before(Metadata/Locator[Color = 'Magenta'][2]/Timecode, ';'), ':',
                            substring-before(substring-after(Metadata/Locator[Color = 'Magenta'][2]/Timecode, ';'), ';'), ':',
                            substring-after(substring-after(Metadata/Locator[Color = 'Magenta'][2]/Timecode, ';'), ';')
                            )"/>
                    </xsl:when>       
                    <xsl:otherwise>18:00:00;00</xsl:otherwise>
                </xsl:choose>
                <xsl:text>@29.97</xsl:text>
            </G1_TC_1_OUT>
........

<G2_TC_1_IN>
                <xsl:choose>
                    <xsl:when test="Metadata/Locator[Color = 'Blue'][1]">
                        <xsl:value-of select="concat(
                            substring-before(Metadata/Locator[Color = 'Blue'][1]/Timecode, ';'), ':',
                            substring-before(substring-after(Metadata/Locator[Color = 'Blue'][1]/Timecode, ';'), ';'), ':',
                            substring-after(substring-after(Metadata/Locator[Color = 'Blue'][1]/Timecode, ';'), ';')
                            )"/>
                    </xsl:when>       
                    <xsl:otherwise>18:00:00;00</xsl:otherwise>
                </xsl:choose>
                <xsl:text>@29.97</xsl:text>
            </G2_TC_1_IN>

Solution

  • To sort you can use apply-templates with a nested sort, e.g.

    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    
        <xsl:strip-space elements="*"/>
        <xsl:output indent="yes"/>
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="Metadata">
            <xsl:copy>
                <xsl:apply-templates select="Locator">
                    <xsl:sort select="Timecode"/>
                </xsl:apply-templates>
            </xsl:copy>
        </xsl:template>
    </xsl:transform>
    

    Online at http://xsltransform.net/bFN1y8X. That should work as long as all numerical values separated by comma have two digits, like your values have (00;02;31;23).