IMPORTANT:
this is not a Support Forum! Experienced users might answer from time to time questions posted here. If you need a professional and reliable answer, or if you want to report a bug, please contact Altova Support instead.

xs:dateTime manipulation using XSLT? Options · View
cycotron69
Posted: Tuesday, October 20, 2009 6:42:05 PM
Rank: Member

Joined: 1/19/2005
Posts: 6
Location: US
Hi,

I want to change all of the xs:dateTime values in an XML to have "00" for seconds using XSLT. For example:

Code:

<Root>
  <timeStamp>2009-10-16T13:08:47Z</timeStamp>
  <schedule>
    <item>
      <name>Name1</name>
      <dateTime>2009-10-16T20:05:30Z</dateTime>
    </item>
    <item>
      <name>Name2</name>
      <dateTime>2009-10-16T122:20:15Z</datetime>
    </item>
  </schedule>
</Root>


should be transformed into:

Code:

<Root>
  <timeStamp>2009-10-16T13:08:00Z</timeStamp>
  <schedule>
    <item>
      <name>Name1</name>
      <dateTime>2009-10-16T20:05:00Z</dateTime>
    </item>
    <item>
      <name>Name2</name>
      <dateTime>2009-10-16T22:20:00Z</datetime>
    </item>
  </schedule>
</Root>


I've been struggling with this one and can't think of a simple way of doing this beside looping through each element and do a string edit. Would it be possible to use a template that can be applied to all xs:dateTime fields?

thanks,

Mike
vlad
Posted: Wednesday, October 21, 2009 7:56:55 AM
Rank: Advanced Member

Joined: 12/13/2005
Posts: 2,856
Location: Mauritius
With XSLT2 you can indeed define templates based on element types. With XSLT1 there is no such possibility
Martin Honnen
Posted: Wednesday, October 21, 2009 10:39:21 AM
Rank: Advanced Member

Joined: 6/10/2007
Posts: 36
Here is an XSLT 2.0 stylesheet that should do what you asked for:
Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xsd">
 
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@*, node()"/>
    </xsl:copy>
  </xsl:template>
 
  <xsl:template match="*[. castable as xsd:dateTime]">
    <xsl:variable name="dt" as="xsd:dateTime" select="xsd:dateTime(.)"/>
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:value-of select="$dt - xsd:dayTimeDuration(concat('PT', seconds-from-dateTime($dt), 'S'))"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
Martin Honnen
Posted: Wednesday, October 21, 2009 11:06:23 AM
Rank: Advanced Member

Joined: 6/10/2007
Posts: 36
Additionally, with schema aware processing, if you provide a scheme like the following:
Code:
<xsd:schema
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 
  <xsd:element name="Root">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="timeStamp" type="xsd:dateTime"/>
        <xsd:element name="schedule">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="item" maxOccurs="unbounded">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="name" type="xsd:string"/>
                    <xsd:element name="dateTime" type="xsd:dateTime"/>
                  </xsd:sequence>
                </xsd:complexType>
              </xsd:element>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

</xsd:schema>

and then an instance document refers to that schema
Code:
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="schema1.xsd">
  <timeStamp>2009-10-16T13:08:47Z</timeStamp>
  <schedule>
    <item>
      <name>Name1</name>
      <dateTime>2009-10-16T20:05:30Z</dateTime>
    </item>
    <item>
      <name>Name2</name>
      <dateTime>2009-10-16T22:20:15Z</dateTime>
    </item>
  </schedule>
</Root>

then you can write the stylesheet as follows:
Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xsd">
 
  <xsl:output indent="yes"/>
 
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@*, node()"/>
    </xsl:copy>
  </xsl:template>
 
  <xsl:template match="*[. instance of xsd:dateTime]">
    <xsl:variable name="dt" as="xsd:dateTime" select="data(.)"/>
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:value-of select="$dt - xsd:dayTimeDuration(concat('PT', seconds-from-dateTime($dt), 'S'))"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
cycotron69
Posted: Wednesday, October 21, 2009 3:41:48 PM
Rank: Member

Joined: 1/19/2005
Posts: 6
Location: US
Hi Martin, thanks for your response, that was great. It works mostly, but I ran into a little problem when I use a XML with a node like below. Seems the script will collapse all of the child nodes if the nested construct contains only a single dateTime element.

Code:

<Root>

  <withOutString>
    <oneDateElement>
      <time>2009-09-04T09:12:38</time>
    </oneDateElement>
  </withOutString>

  <withString>
    <string>OK</string>
    <time>2009-09-04T09:12:38</time>
  </withString>

  <multipleDates>
    <time>2009-09-04T09:12:38</time>
    <time>2009-09-04T09:12:38</time>
  </multipleDates>

</Root>


and the result I got was

Code:

<Root>

  <withOutString>2009-09-04T09:12:00</withOutString>

  <withString>
    <string>OK</string>
    <time>2009-09-04T09:12:00</time>
  </withString>

  <multipleDates>
    <time>2009-09-04T09:12:00</time>
    <time>2009-09-04T09:12:00</time>
  </multipleDates>

</Root>


Martin Honnen
Posted: Wednesday, October 21, 2009 5:33:13 PM
Rank: Advanced Member

Joined: 6/10/2007
Posts: 36
Change template
Code:

  <xsl:template match="*[. castable as xsd:dateTime]">
    <xsl:variable name="dt" as="xsd:dateTime" select="xsd:dateTime(.)"/>
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:value-of select="$dt - xsd:dayTimeDuration(concat('PT', seconds-from-dateTime($dt), 'S'))"/>
    </xsl:copy>
  </xsl:template>

to
Code:

  <xsl:template match="*[not(*)][. castable as xsd:dateTime]">
    <xsl:variable name="dt" as="xsd:dateTime" select="xsd:dateTime(.)"/>
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:value-of select="$dt - xsd:dayTimeDuration(concat('PT', seconds-from-dateTime($dt), 'S'))"/>
    </xsl:copy>
  </xsl:template>
cycotron69
Posted: Wednesday, October 21, 2009 5:54:12 PM
Rank: Member

Joined: 1/19/2005
Posts: 6
Location: US
Sweet! Works like a charm. Thanks very much!
cycotron69
Posted: Friday, October 23, 2009 3:56:27 PM
Rank: Member

Joined: 1/19/2005
Posts: 6
Location: US
Hi Martin,

so turn out the XSLT engine we are using doesn't fully support XSLT 2.0, so I'm not able to use "castable". I've been playing around with using regex to do match & replace on the dates, but I have very little experience with using regex with XSLT. Below is the regex match and replace expression I came up with, any idea on how to get it to work in an XSLT script? This would work for XSLT 1.0 too then right?

Match Expression: (^\-?\d{4}\-\d{2}\-\d{2}T\d{2}:\d{2}:)(\d{2})((\.\d+)?(Z|([\+\-]{1}\d{2}:\d{2}))?$)
Replace Expression: $100$3

Thanks for your help.

Mike
Martin Honnen
Posted: Friday, October 23, 2009 5:03:49 PM
Rank: Advanced Member

Joined: 6/10/2007
Posts: 36
Pure XSLT/XPath 1.0 does not have any support for regular expressions. So unless your XSLT processor provides regular expression support with extension functions I don't see how regular expressions help with an XSLT 1.0 processor.
Which XSLT processor do you use exactly?
cycotron69
Posted: Friday, October 30, 2009 7:08:26 PM
Rank: Member

Joined: 1/19/2005
Posts: 6
Location: US
Thanks Martin, just confirmed with our admin that they are using XLST 1.0 engine, so looks like there's not much that can be done now, but the scripts is pretty cool, I'll save it for another day. Thanks for all the help!
forumuser18
Posted: Tuesday, January 12, 2010 4:16:49 PM
Rank: Newbie

Joined: 1/8/2010
Posts: 6
I got this error:

Unable to load a schema with target namespace '' from 'dateTime.xsd'.

dateTime.xsd is your post from October 21, 2009 12:06:23 PM.

Did you get this error message as well?
Users browsing this topic
guest

Forum Jump
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Use of the Altova User Forum(s) is governed by the Altova Terms of Use.