Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.8k views
in Technique[技术] by (71.8m points)

xml - XSLT Date Formatting

I have had a look at various suggestions on here but none really help my problem. Due to the sources my XML comes from i can receive dates in the following three formats;

04-04-2014(DD-MM-YYYY)
04-Apr-2014(DD-MMM-YYYY)
2014-04-04(YYYY-MM-DD)

I would like to have a function or simple command that will change all of these (other than the third, yet able to recognize that the third is correct) into YYYY-MM-DD

I have a long winded When/when/when to do this currently, but there must be an easier way. My current XSLT does the following;

<xsl:choose>
    <xsl:when test="contains(date, 'Jan')">
        <xsl:value-of select="concat(substring(date,6),'-01-',substring(date,1,2))" />
    </xsl:when>
    <xsl:when test="contains(date, 'Feb')">
        <xsl:value-of select="concat(substring(date,6),'-02-',substring(date,1,2))" />
    </xsl:when>
    <xsl:when test="contains(date, 'Mar')">
        <xsl:value-of select="concat(substring(date,6),'-03-',substring(date,1,2))" />
    </xsl:when>
    <xsl:when test="contains(date, 'Apr')">
        <xsl:value-of select="concat(substring(date,6),'-04-',substring(date,1,2))" />
    </xsl:when>
    <xsl:when test="contains(date, 'May')">
        <xsl:value-of select="concat(substring(date,6),'-05-',substring(date,1,2))" />
    </xsl:when>
    <xsl:when test="contains(date, 'Jun')">
        <xsl:value-of select="concat(substring(date,6),'-06-',substring(date,1,2))" />
    </xsl:when>
    <xsl:when test="contains(date, 'Jul')">
        <xsl:value-of select="concat(substring(date,6),'-07-',substring(date,1,2))" />
    </xsl:when>
    <xsl:when test="contains(date, 'Aug')">
        <xsl:value-of select="concat(substring(date,6),'-08-',substring(date,1,2))" />
    </xsl:when>
    <xsl:when test="contains(date, 'Sep')">
        <xsl:value-of select="concat(substring(date,6),'-09-',substring(date,1,2))" />
    </xsl:when>
    <xsl:when test="contains(date, 'Oct')">
        <xsl:value-of select="concat(substring(date,6),'-10-',substring(date,1,2))" />
    </xsl:when>
    <xsl:when test="contains(date, 'Nov')">
        <xsl:value-of select="concat(substring(date,6),'-11-',substring(date,1,2))" />
    </xsl:when>
    <xsl:when test="contains(date, 'Dec')">
        <xsl:value-of select="concat(substring(date,6),'-12-',substring(date,1,2))" />
    </xsl:when>
    <xsl:when test="string-length($dateStart) = 2">
        <xsl:value-of select="concat(substring(date,7),'-',substring(date,4,2),'-',substring(date,1,2))" />
    </xsl:when>
    <xsl:otherwise>
        <xsl:value-of select="date"/>
    </xsl:otherwise>
</xsl:choose>

So this will check if the date contains any months as JAN,Feb etc. and then if not, check if the first number up to - is 2 characters (DD) and format, other wise it assumes it is YYYY-MM-DD already and outputs it as it is.

I have tried - <xsl:value-of select = "format-dateTime(date, '[Y0001]-[MN]-[D01]')"/> But this complains that the Dates year is not long enough (as date is being treated as a datetime, which should be in format YYYY-MM-DD

Thanks to Ian roberts Answer below, i created the below to deal with a few more scenarios and group the outputs together;

<xsl:variable name="months" select="('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')" />
<xsl:analyze-string select="date" flags="x"
       regex="^(
            (dd)-(dd)-(dddd)
          | (dd)-([A-Za-z]{{3}})-(dddd)
          | (dddd)-(dd)-(dd)
          | (dddd)-([A-Za-z]{{3}})-(dd)
          | (dd)([A-Za-z]{{3}})(dddd)
          | (dddd)([A-Za-z]{{3}})(dd))$">
        <xsl:matching-substring>
            <xsl:value-of select="if (regex-group(4)) then concat(regex-group(4),'-',regex-group(3),'-',regex-group(2)) else ''"/>
            <xsl:value-of select="if (regex-group(7)) then concat(regex-group(7),'-',format-number(index-of($months, regex-group(6)), '00'),'-',regex-group(5)) else ''"/>
            <xsl:value-of select="if (regex-group(8)) then concat(regex-group(8),'-',regex-group(9),'-',regex-group(10)) else ''"/>
            <xsl:value-of select="if (regex-group(11)) then concat(regex-group(11),'-',format-number(index-of($months, regex-group(12)), '00'),'-',regex-group(13)) else ''"/>
            <xsl:value-of select="if (regex-group(16)) then concat(regex-group(16),'-',format-number(index-of($months, regex-group(15)), '00'),'-',regex-group(14)) else ''"/>
            <xsl:value-of select="if (regex-group(17)) then concat(regex-group(17),'-',format-number(index-of($months, regex-group(18)), '00'),'-',regex-group(19)) else ''"/>
        </xsl:matching-substring>
    </xsl:analyze-string>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Even in XSLT 1.0, the problem becomes fairly trivial once you focus on the structure of the different formats rather than on their contents:

<xsl:template name="normalize-datestring">
<xsl:param name="datestring"/>
        <xsl:choose>
            <xsl:when test="string-length(substring-before($datestring, '-')) = 4">
            <!-- this is YYYY-MM-DD; copy as is -->
                <xsl:value-of select="$datestring" />
            </xsl:when>
            <xsl:when test="string-length($datestring) = 10">
            <!-- this is DD-MM-YYYY; reorder -->
                <xsl:value-of select="substring($datestring, 7, 4)" />
                <xsl:text>-</xsl:text>
                <xsl:value-of select="substring($datestring, 4, 2)" />
                <xsl:text>-</xsl:text>
                <xsl:value-of select="substring($datestring, 1, 2)" />
            </xsl:when>
            <xsl:otherwise>
            <!-- this is DD-MMM-YYYY; reorder and calculate month number-->
                <xsl:value-of select="substring($datestring, 8, 4)" />
                <xsl:text>-</xsl:text>
                <xsl:variable name="mmm" select="substring($datestring, 4, 3)" />
                <xsl:variable name="m" select="string-length(substring-before('JanFebMarAprMayJunJulAugSepOctNovDec', $mmm)) div 3 + 1" />
                <xsl:value-of select="format-number($m, '00')" />
                <xsl:text>-</xsl:text>
                <xsl:value-of select="substring($datestring, 1, 2)" />
            </xsl:otherwise>
        </xsl:choose>
</xsl:template>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...