XSLT Informal Time Translation - datetime

I'm currently working on a translation of documents for importing as XML to another system, and this involves the translation of a quite informal representation of time, such as the following:
<estimated-time>15 mins<estimated-time>
And I need to translate this to something like the following:
<tr:estimated_time>00:15:00</tr:estimated_time>
I've messed around with tokenizing, substrings, and the various time functions and haven't been able to come up with anything, though I am quite inexperienced in XSLT.
Following Jirka's answer, I tried the following:
<xsl:template match="estimated-time">
<tr:estimated_time>
<xsl:value-of select="time:parseTime(./text(), 'hours')"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="time:parseTime(./text(), 'mins')"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="time:parseTime(./text(), 'seconds')"/>
</tr:estimated_time>
</xsl:template>
<xsl:function name="time:parseTime">
<xsl:param name="testedString"/>
<xsl:param name="lookingFor"/>
<xsl:variable name="tokens" select="tokenize($testedString, ' ')" />
<xsl:variable name="out">
<xsl:choose>
<xsl:when test="$tokens[. = $lookingFor]">
<xsl:variable name="pos" select="index-of($tokens, $lookingFor)-1"/>
<xsl:value-of select="$tokens[$pos]"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>00</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="if (string-length($out)=1) then concat('0', $out) else $out"/>
</xsl:function>
Which always resulted in:
<tr:estimated_time>00:00:00</tr:estimated_time>
Any assistance would be greatly appreciated.
Update: it works! There were some weird newlines all over the original that I hadn't spotted, which were preventing it from working.

Might be there is a more sofisticated or cleaner solution but using tokenizing it should be done for example in this way
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:tst="test">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<times>
<xsl:apply-templates select="times/time" />
</times>
</xsl:template>
<xsl:template match="time">
<time>
<xsl:value-of select="tst:getSomething(.,'hours')" />
<xsl:text>:</xsl:text>
<xsl:value-of select="tst:getSomething(.,'mins')" />
<xsl:text>:</xsl:text>
<xsl:value-of select="tst:getSomething(.,'sec')" />
</time>
</xsl:template>
<xsl:function name="tst:getSomething">
<xsl:param name="testedString" />
<xsl:param name="lookingFor" />
<xsl:variable name="tokens" select="tokenize($testedString, ' ')" />
<xsl:variable name="tmp">
<xsl:choose>
<xsl:when test="$tokens[. = $lookingFor]">
<xsl:variable name="pos" select="index-of($tokens, $lookingFor) - 1" />
<xsl:value-of select="$tokens[$pos]" />
</xsl:when>
<xsl:otherwise>
<xsl:text>00</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="if (string-length($tmp) = 1) then concat('0', $tmp) else $tmp" />
</xsl:function>
</xsl:stylesheet>
It produces output
<?xml version="1.0" encoding="UTF-8"?>
<times>
<time>05:30:00</time>
<time>00:05:00</time>
</times>

Related

Combining XML Nodes into a single node with an XSLT

I'm trying to edit some XML with a transform but I'm struggling to achieve my desired results.
I have some XML:
<FX>
<Order ATTRIBUTE1="ACTIVE" ATTRIBUTE2="CCY" />
<Attribute NAME="N1" VALUE="V1" />
<Attribute NAME="N2" VALUE="V2" />
<Attribute NAME="N3" VALUE="V3" />
</FX>
And I want to transform it to look like:
<FX>
<Order ATTRIBUTE1="ACTIVE" ATTRIBUTE2="CCY" />
<Attribute NAME="N1, N2, N3" VALUE="V1,V2,V3" />
</FX>
Is this possible? Can anyone offer any suggestions on how to do this with a transform?
You can use the following, Asp.NET compatable, XSLT-1.0 stylesheet to perform an XSLT transformation from your source XML to your destination XML:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/FX">
<xsl:copy>
<xsl:copy-of select="Order" />
<Attribute>
<xsl:attribute name="NAME">
<xsl:for-each select="Attribute">
<xsl:value-of select="#NAME" />
<xsl:if test="position() != last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:attribute>
<xsl:attribute name="VALUE">
<xsl:for-each select="Attribute">
<xsl:value-of select="#VALUE" />
<xsl:if test="position() != last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:attribute>
</Attribute>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Its output is:
<FX>
<Order ATTRIBUTE1="ACTIVE" ATTRIBUTE2="CCY"/>
<Attribute NAME="N1, N2, N3" VALUE="V1,V2,V3"/>
</FX>
In general, if you want to transform some nodes but keep the rest you use the identity transformation template as the starting point and then add templates that change those nodes you want to change:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="FX/Attribute[1]">
<xsl:copy>
<xsl:apply-templates select="#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="FX/Attribute[position() > 1]"/>
<xsl:template match="FX/Attribute[1]/#*">
<xsl:attribute name="{name()}">
<xsl:for-each select=". | ../following-sibling::Attribute/#*[name() = name(current())]">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/jyH9rNk

Recursive loop in Xslt 1.0

I am working on a recursive loop. Below is the sample code.
The loop gets executed only once. It is not executing until it reaches the maximum count (20 times).
Can you please help if this is an issue?
Thanks,
Raj
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:xdoxslt='http://www.oracle.com/XSL/Transform/java/oracle.apps.xdo.template.rtf.XSLTFunctions'>
<xsl:output method="text" omit-xml-declaration="yes" />
<xsl:variable name="nl">
<xsl:value-of select="'
'"/>
<xsl:text xml:space="preserve">
</xsl:text>
</xsl:variable>
<xsl:template match = "ARCHIVE_CHEQUE_WRITER">
<xsl:for-each select="CHEQUE">
<xsl:variable name="ded" select="./AC_DEDUCTIONS"/>
<xsl:variable name="dedcount" select="count($ded)"/>
<xsl:variable name="earn" select="./AC_EARNINGS"/>
<xsl:variable name="earncount" select="count($earn)"/>
<xsl:value-of select="$dedcount"/>
<xsl:value-of select="$nl"/>
<xsl:value-of select="$earncount"/>
<xsl:value-of select="$nl"/>
<xsl:text>Starting New Record*******</xsl:text>
<xsl:value-of select="$nl"/>
<xsl:for-each select="./AC_DEDUCTIONS">
<xsl:text>This is sample template</xsl:text>
<xsl:value-of select="$nl"/>
</xsl:for-each>
<xsl:value-of select="$nl"/>
<xsl:value-of select="$nl"/>
<xsl:call-template name="recursive-loop">
<xsl:with-param name="pCount" select="20"/>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="recursive-loop">
<xsl:param name="pStart" select="1"/>
<xsl:param name="pCount"/>
<xsl:text> value of parameters</xsl:text>
<xsl:value-of select="$nl"/>
<xsl:value-of select="$pStart"/>
<xsl:value-of select="$pCount"/>
<xsl:value-of select="$nl"/>
<xsl:if test="$pCount > pStart">
<xsl:call-template name="recursive-loop">
<xsl:with-param name="pStart" select="$pStart+1"/>
<xsl:with-param name="pCount" select="$pCount"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
You forgot to use $ for variable pStart in the template
<xsl:if test="$pCount > $pStart">
<xsl:call-template name="recursive-loop">
<xsl:with-param name="pStart" select="$pStart+1"/>
<xsl:with-param name="pCount" select="$pCount"/>
</xsl:call-template>
</xsl:if>

Display Images from media directory using media picker not working

I am using Umbraco v6.1.6 and what I want is simply display the images from the media directory I select using media picker.
The content of media directory is as below:
And I have created an XSLT file named ImageSlider.xslt and the content of that file are as below:
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:umb="urn:umbraco.library"
exclude-result-prefixes="umb"
>
<xsl:output method="html" indent="yes" omit-xml-declaration="yes" />
<xsl:param name="currentPage" />
<xsl:template match="/">
<xsl:variable name="media" select="umb:GetMedia(1088, 0)" />
<xsl:if test="$media">
<img src="{$media/umbracoFile}" alt="{$media/altText}" />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
here 1088 is the ID of the banner directory but it is not working at all. I am new to this.
Can anyone please help me ?
I'm assuming you want to select the folder and list all images underneath it. At the moment, your code is just trying to display the folder. You need something like this...
In my example, I'm using a multi-node tree picker and you can select images and folders, rendering out a csv. It will loop through it all and list out all the images
<xsl:for-each select="$source/value">
<xsl:variable name="imageId" select="number(current())" />
<xsl:if test="$imageId > 0">
<xsl:variable name="media" select="umbraco.library:GetMedia($imageId, 0)" />
<xsl:choose>
<xsl:when test="local-name($media) = 'Image'">
<xsl:call-template name="ImageBox">
<xsl:with-param name="imageId" select="$imageId"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="local-name($media) = 'Folder'">
<xsl:call-template name="LoopFolders">
<xsl:with-param name="folderId" select="$imageId"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="LoopFolders">
<xsl:param name="folderId"/>
<xsl:variable name="media" select="umbraco.library:GetMedia($folderId, 0)" />
<xsl:variable name="alt" select="$media/#nodeName" />
<div id="gallery">
<xsl:for-each select="umbraco.library:GetMedia($folderId, true())/Image">
<xsl:call-template name="ImageBox">
<xsl:with-param name="imageId" select="number(#id)"/>
</xsl:call-template>
</xsl:for-each>
</div>
</xsl:template>
<xsl:template name="ImageBox">
<xsl:param name="imageId"/>
<xsl:if test="$imageId > 0">
<xsl:variable name="media" select="umbraco.library:GetMedia($imageId, 0)" />
<xsl:if test="$media">
<xsl:variable name="url" select="$media/umbracoFile" />
<xsl:variable name="width" select="$media/umbracoWidth" />
<xsl:variable name="height" select="$media/umbracoHeight" />
<xsl:variable name="alt" select="$media/#nodeName" />
<img src="{$url}" alt="{$alt}" width="{$width}" height="{$height}" />
</xsl:if>
</xsl:if>
</xsl:template>

Issues with publishing an RSS feed

I'm having trouble publishing an RSS feed from my Umbraco site. I found this Umbraco.TV video and tried to follow the instructions there using an XSLT selector to select all nodes of a give type, like so:
umbraco.library.GetXmlAll()/node [#nodeTypeAlias='Alias]/node
As sugested here but that didn't work. Apparently the schema has changed or something. When this didn't work I looked for a plugin to do this kind of stuff and was amazed to find just 2 plugins, both of them with little-to-no documentation and neither seemed to work (first plugin, second plugin).
So once and for all, I'd like to have a definite answer - how does one publish an RSS feed in Umbraco?
Here's an XSLT that we use for News Items RSS (News Items are under a News Page). Let me know if that helps. I also have versions for Blogs.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rssdatehelper="urn:rssdatehelper"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets"
exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets ">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="currentPage"/>
<!-- Update these variables to modify the feed -->
<xsl:variable name="RSSNoItems" select="/macro/RSSNoItems"/>
<xsl:variable name="RSSTitle" select="/macro/RSSTitle"/>
<xsl:variable name="SiteURL" select="concat('http://',umbraco.library:RequestServerVariables('HTTP_HOST'))"/>
<xsl:variable name="RSSDescription" select="/macro/RSSDescription"/>
<xsl:variable name="source" select="/macro/source"/>
<!-- This gets all news and events and orders by updateDate to use for the pubDate in RSS feed -->
<xsl:variable name="pubDate">
<xsl:for-each select="umbraco.library:GetXmlNodeById($source)/* [#isDoc and string(umbracoNaviHide) != '1']">
<xsl:sort select="./newsDate" order="descending" />
<xsl:if test="position() = 1">
<xsl:value-of select="./newsDate" />
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<!-- change the mimetype for the current page to xml -->
<xsl:value-of select="umbraco.library:ChangeContentType('text/xml')"/>
<xsl:text disable-output-escaping="yes"><?xml version="1.0" encoding="UTF-8"?></xsl:text>
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
>
<channel>
<title>
<xsl:value-of select="$RSSTitle"/>
</title>
<link>
<xsl:value-of select="$SiteURL"/>
</link>
<pubDate>
<xsl:value-of select="$pubDate"/>
</pubDate>
<generator>umbraco v4</generator>
<description>
<xsl:value-of select="$RSSDescription"/>
</description>
<language>en</language>
<xsl:for-each select="umbraco.library:GetXmlNodeById($source)/* [#isDoc and string(umbracoNaviHide) != '1']">
<xsl:sort select="./newsDate" order="descending" />
<xsl:if test="position() <= $RSSNoItems">
<xsl:call-template name="RSSitem">
<xsl:with-param name="node" select="current()"/>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</channel>
</rss>
</xsl:template>
<xsl:template match="node">
<xsl:if test="position() <= $RSSNoItems">
<item>
<title>
<xsl:value-of select="#nodeName"/>
</title>
<link>
<xsl:value-of select="$SiteURL"/>
<xsl:value-of select="umbraco.library:NiceUrl(#id)"/>
</link>
<pubDate>
<xsl:value-of select="umbraco.library:FormatDateTime(./newsDate,'r')" />
</pubDate>
<guid>
<xsl:value-of select="$SiteURL"/>
<xsl:value-of select="umbraco.library:NiceUrl(#id)"/>
</guid>
<content:encoded>
<xsl:value-of select="concat('<![CDATA[ ', ./bodyText,']]>')" disable-output-escaping="yes"/>
</content:encoded>
</item>
</xsl:if>
</xsl:template>
<xsl:template name="RSSitem">
<xsl:param name="node"/>
<item>
<title>
<xsl:value-of select="$node/#nodeName"/>
</title>
<link>
<xsl:value-of select="$SiteURL"/><xsl:value-of select="umbraco.library:NiceUrl($node/#id)"/>
</link>
<pubDate>
<xsl:value-of select="umbraco.library:FormatDateTime(./newsDate,'r')"/>
</pubDate>
<dc:creator><xsl:value-of select="#writerName"/></dc:creator>
<xsl:for-each select="umbraco.library:Split($node/categories, ',')/value">
<xsl:sort data-type="text" order="ascending"/>
<category>
<xsl:value-of select="current()"/>
</category>
</xsl:for-each>
<guid>
<xsl:value-of select="$SiteURL"/><xsl:value-of select="umbraco.library:NiceUrl($node/#id)"/>
</guid>
<description>
<xsl:value-of select="concat('<![CDATA[ ', $node/summary,']]>')" disable-output-escaping="yes"/>
</description>
<content:encoded>
<xsl:value-of select="concat('<![CDATA[ ', $node/bodyText,']]>')" disable-output-escaping="yes"/>
</content:encoded>
</item>
</xsl:template>
</xsl:stylesheet>

Trim first 10 characters off the title of RSS feed

I'm trying to write some xsl to style an RSS feed. I need to trim the first 10 characters off the title of each item.
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/rss">
<ul>
<xsl:for-each select="channel/item">
<li><strong><xsl:value-of select="title"/>
</strong>
More</li>
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template name="trimtitle">
<xsl:param name="string" select="." />
<xsl:if test="$string">
<xsl:text>Foo</xsl:text>
<xsl:call-template name="trimtitle">
<xsl:with-param name="string" select="substring($string, 10)" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="title">
<xsl:call-template name="title" />
<xsl:value-of select="." />
</xsl:template>
</xsl:stylesheet>
I think you should write your substring function as this:
substring($string,1, 10)
Look at here
http://www.zvon.org/xxl/XSLTreference/Output/function_substring.html
What are you doing in your trimtitle template?
Why are you calling trimtitle recursive..?
The easiest way to show a trimmed string is with:
<xsl:value-of select="substring(title,0,10)"/>

Resources