Link to home
Start Free TrialLog in
Avatar of greddin
greddinFlag for United States of America

asked on

How to convert a Month number into a Month name

I have an XML and XSL files below.  Right now I am only displaying the Title node from the XML file. But I would also like to display the date. But not as 09/09/2003, but as September 09, 2003. Using what I already have below can you show me how to display the date at this?


Here is my current XML file:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="simple1.xsl" ?>
<Index>
  <Article ID="breast_sept03">
    <Title>Moderate Exercise Decreases Risk of Breast Cancer</Title>
    <URL>http://www.cancerconsultants.com/xml/breast_sept03.xml</URL>
    <PublicationDate>
        <Year>2003</Year>
        <Month>09</Month>
        <Day>09</Day>
    </PublicationDate>
  </Article>
  <Article ID="breast_aug03">
    <Title>Childbearing Does Not Increase Mortality</Title>
    <URL>http://www.cancerconsultants.com/xml/breast_aug03.xml</URL>
    <PublicationDate>
      <Year>2003</Year>
      <Month>08</Month>
      <Day>04</Day>
    </PublicationDate>
  </Article>
  <Article ID="breast_aug03_2">
    <Title>Largest Analysis To Date Indicates</Title>
    <URL>http://www.cancerconsultants.com/xml/breast_aug03_2.xml</URL>
    <PublicationDate>
      <Year>2003</Year>
      <Month>08</Month>
      <Day>06</Day>
    </PublicationDate>
  </Article>
  <Article ID="breast_aug03_3">
    <Title>Preoperative MRI Improves Staging Accuracy in Breast Cancer </Title>
    <URL>http://www.cancerconsultants.com/xml/breast_aug03_3.xml</URL>
    <PublicationDate>
      <Year>2003</Year>
      <Month>08</Month>
      <Day>11</Day>
    </PublicationDate>
  </Article>
</Index>

Here is my current XSLT file:

<?xml version="1.0" encoding="ISO-8859-1"?>

<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/xhtml1/strict">

<div class="newsitem">
<xsl:for-each select="Index/Article">
    <xsl:value-of select="Title"/>
</xsl:for-each>
</div>

</html>
SOLUTION
Avatar of rdcpro
rdcpro
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Oh, if you want to drop the leading zeros, you'll have to do a little extra processing to format the number.

Regards,
Mike Sharp
There's also a "pure" XSLT approach, too, but it's a bit more complex.  As long as your XSLT doesn't have to be portable, and as long as you don't code side-effects, extension functions are ok.

Regards,
Mike Sharp
Avatar of greddin

ASKER

Can you describe what you mean by portable xslt?

Thanks.
Meaing your XSLT will work on MSXML or Xalan, or another XSL processor.  Most of the time, I'm developing for a particular platform, but there are those who insist on creating code that will run on multiple platforms.  As long as you're planning on using Microsoft's MSXML or .NET parsers, you can stick with the extension functions.  But check out EXSLT's extensions.  They've tried to create a cross-platform extension framework, though not all processors support it.  

The one extension function you can pretty well count on being supported on all XSL processors is the node-set() function.  However, even then the function is scoped to a namespace that precludes it from being used on other platforms without changing the namespace.  

One nice thing about the Javascript Date object, is that it has built-in validation.  That is, if you try to parse a date that doesn't make sense, it returns null, I believe.  You might even be able to trap an exception using a try-catch block.

Regards,
Mike Sharp
Avatar of Node
Node

Hi all,

A simple pure xsl approach could be to call a template to convert the month to the corresponding name, the content of your xsl would become :

--------------------------------------------------------------------------------------------------------------------
<div class="newsitem">
    <xsl:for-each select="Index/Article">
        <xsl:apply-templates select="PublicationDate/Month" mode="convertToName"/> <xsl:value-of select="PublicationDate/Day" />, <xsl:value-of select="PublicationDate/Year" />
        <xsl:value-of select="Title"/>
    </xsl:for-each>
</div>

<!-- template to convert the month number to the corresponding name -->
<xsl:template match="Month" mode="convertToName">

    <!-- make sure the month has 2 digits -->
    <xsl:variable name="twoDigitsMonth">
        <xsl:choose>
            <!-- adds a leading zero when there's only one digit -->
            <xsl:when test="string-length(.) = 1">
                <xsl:value-of select="concat('0', .)" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="." />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>

    <!-- outputs the corresponding label -->
    <xsl:choose>
        <xsl:when test="$twoDigitsMonth='01'">january</xsl:when>
        <xsl:when test="$twoDigitsMonth='02'">february</xsl:when>
        <xsl:when test="$twoDigitsMonth='03'">march</xsl:when>
        <xsl:when test="$twoDigitsMonth='04'">april</xsl:when>
        <xsl:when test="$twoDigitsMonth='05'">may</xsl:when>
        <xsl:when test="$twoDigitsMonth='06'">june</xsl:when>
        <xsl:when test="$twoDigitsMonth='07'">july</xsl:when>
        <xsl:when test="$twoDigitsMonth='08'">august</xsl:when>
        <xsl:when test="$twoDigitsMonth='09'">september</xsl:when>
        <xsl:when test="$twoDigitsMonth='10'">october</xsl:when>
        <xsl:when test="$twoDigitsMonth='11'">november</xsl:when>
        <xsl:when test="$twoDigitsMonth='12'">december</xsl:when>

        <!-- when nothing match, outputs the month unchanged -->
        <xsl:otherwise>
            <xsl:value-of select="." />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
--------------------------------------------------------------------------------------------------------------------

for instance. If there is a problem with the month number, it will remain unchanged, but you can also do something else to "catch" this error.



Avatar of greddin

ASKER

I haven't decided what approach to make yet, but I just tried the solution from "Node" above.

I get the following error: "Keyword xsl:template may not be used here".

Here is my complete revised code that's giving the error:

<?xml version="1.0" encoding="ISO-8859-1"?>

<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/xhtml1/strict">

<div class="newsitem">
    <xsl:for-each select="Index/Article">
        <xsl:apply-templates select="PublicationDate/Month" mode="convertToName"/> <xsl:value-of select="PublicationDate/Day" />, <xsl:value-of select="PublicationDate/Year" />
        <xsl:value-of select="Title"/>
    </xsl:for-each>
</div>

<!-- template to convert the month number to the corresponding name -->
<xsl:template match="Month" mode="convertToName">

    <!-- make sure the month has 2 digits -->
    <xsl:variable name="twoDigitsMonth">
        <xsl:choose>
            <!-- adds a leading zero when there's only one digit -->
            <xsl:when test="string-length(.) = 1">
                <xsl:value-of select="concat('0', .)" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="." />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>

    <!-- outputs the corresponding label -->
    <xsl:choose>
        <xsl:when test="$twoDigitsMonth='01'">january</xsl:when>
        <xsl:when test="$twoDigitsMonth='02'">february</xsl:when>
        <xsl:when test="$twoDigitsMonth='03'">march</xsl:when>
        <xsl:when test="$twoDigitsMonth='04'">april</xsl:when>
        <xsl:when test="$twoDigitsMonth='05'">may</xsl:when>
        <xsl:when test="$twoDigitsMonth='06'">june</xsl:when>
        <xsl:when test="$twoDigitsMonth='07'">july</xsl:when>
        <xsl:when test="$twoDigitsMonth='08'">august</xsl:when>
        <xsl:when test="$twoDigitsMonth='09'">september</xsl:when>
        <xsl:when test="$twoDigitsMonth='10'">october</xsl:when>
        <xsl:when test="$twoDigitsMonth='11'">november</xsl:when>
        <xsl:when test="$twoDigitsMonth='12'">december</xsl:when>

        <!-- when nothing match, outputs the month unchanged -->
        <xsl:otherwise>
            <xsl:value-of select="." />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</html>
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
You can also do this the W3C way, by storing the month names in a separate XML file called Locale.xml. (I used French month names.)

<?xml version="1.0" encoding="UTF-8"?>
<MonthNames>
      <MonthName MonthNumber="01">janvier</MonthName>
      <MonthName MonthNumber="02">f&#233;vrier</MonthName>
      <MonthName MonthNumber="03">mars</MonthName>
      <MonthName MonthNumber="04">avril</MonthName>
      <MonthName MonthNumber="05">mai</MonthName>
      <MonthName MonthNumber="06">juin</MonthName>
      <MonthName MonthNumber="07">juillet</MonthName>
      <MonthName MonthNumber="08">aou&#251;t</MonthName>
      <MonthName MonthNumber="09">septembre</MonthName>
      <MonthName MonthNumber="10">octobre</MonthName>
      <MonthName MonthNumber="11">novembre</MonthName>
      <MonthName MonthNumber="12">d&#233;cembre</MonthName>
</MonthNames>

Then you retrieve the month name from the XSLT stylesheet using the following code:

<xsl:variable name="FrenchMonth" select="document('Locale.xml')/MonthNames"/>

Here is a routine to format the month:

<xsl:template name="FrenchDate">
<xsl:variable name="year" select="substring-before(., '-')"/>
<xsl:variable name="month" select="substring(.,6,2)"/>
<xsl:variable name="day" select="substring(.,9,2)" />
<xsl:value-of select="$day"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$FrenchMonth/MonthName[@MonthNumber=$month]"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$year"/>
</xsl:template>

Then you call the routine with this code:

      <xsl:for-each select="DateDue">
           <xsl:call-template name="FrenchDate"/>
                </xsl:for-each>

I have tried this and it works.

Maria