|
|
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
|
|
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
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
Rank: Member
Joined: 1/19/2005 Posts: 6 Location: US
|
Sweet! Works like a charm. Thanks very much!
|
|
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
|
|
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?
|
|
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!
|
|
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?
|
|
|
guest |