XSLT Comma separating list, without grouping - json

I'm trying to convert the following XML document:
<method>
<desc_signature>
<desc_name>
Some method name
</desc_name>
</desc_signature>
<desc_content>
<paragraph>Paragraph1</paragraph>
<image>Image1</image>
<paragraph>Paragraph2</paragraph>
<literal_block>Codesnippet1</literal_block>
<image>Image2</image>
<paragraph>Paragraph3</paragraph>
<image>Image3</image>
<literal_block>Codesnippet2</literal_block>
</desc_content>
</method>
To the following JSON format:
{
"title":"Some method name",
"elements":[
"Paragraph1",
"Paragraph2",
"Codesnippet1",
"Paragraph3",
"Codesnippet2",
]
}
What I basically want to achieve, is to comma separate a list, but only include paragraph and literal_blocks, and still keeping the original order.
My first attempt was an XSLT that looks like this, with this union selector:
<xsl:for-each select="desc_content/paragraph|desc_content/literal_block">
Like this:
<!-- Method template -->
<xsl:template name="method">
{
"title":"<xsl:value-of select="normalize-space(desc_signature/desc_name)" />",
"elements":[
<xsl:for-each select="desc_content/paragraph|desc_content/literal_block">
<xsl:choose>
<xsl:when test="self::paragraph">
<xsl:call-template name="paragraph"/>
</xsl:when>
<xsl:when test="self::literal_block">
<xsl:call-template name="code"/>
</xsl:when>
</xsl:choose>
<xsl:if test="position()!=last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
]
}
</xsl:template>
However, it seems like it is grouping paragraphs and then literal_blocks:
{
"title":"Some method name",
"elements":[
"Paragraph1",
"Paragraph2",
"Paragraph3",
"Codesnippet1",
"Codesnippet2",
]
}
Another approach was to select all:
<xsl:for-each select="desc_content/*">
That, however, yields too many commas, as position() accounts for all elements, even if not used:
{
"title":"Some method name",
"elements":[
"Paragraph1",,
"Paragraph2",
"Codesnippet1",,
"Paragraph3",,
"Codesnippet2",
]
}
How would I be able to achieve the desired behaviour?
Thanks for the help!
EDIT - XSLT 1.0 solution:
I've solved the issue with the solution from #Christian Mosz, using apply-templates and checking following-sibling:
<!-- Method template -->
<xsl:template name="method">
{
"title":"<xsl:value-of select="normalize-space(desc_signature/desc_name)" />",
"elements":[
<xsl:apply-templates select="desc_content/*"/>
]
}
</xsl:template>
<!-- Paragraph template -->
<xsl:template match="paragraph">
{"paragraph":"<xsl:value-of select="normalize-space()"/>"}
<xsl:if test="following-sibling::paragraph|following-sibling::literal_block">,</xsl:if>
</xsl:template>
<!-- Code snippet template -->
<xsl:template match="literal_block">
{"code":"<xsl:call-template name="code"/>"}
<xsl:if test="following-sibling::paragraph|following-sibling::literal_block">,</xsl:if>
</xsl:template>
For XSLT 3.0, please check approved answer.

Using XSLT 3 (e.g. with Saxon 9.8 or later or AltovaXML 2017 R3 or later) you have two options, you can either construct an XPath 3.1 map:
map {
'title' : normalize-space(desc_signature/desc_name),
'elements' : array {
data(desc_content/(paragraph | literal_block))
}
}
i.e.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output method="json" indent="yes" />
<xsl:template match="method">
<xsl:sequence
select="map {
'title' : normalize-space(desc_signature/desc_name),
'elements' : array {
data(desc_content/(paragraph | literal_block))
}
}"/>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/pNmC4HJ
or you transform to the XML representation of JSON the xml-to-json functions supports:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.w3.org/2005/xpath-functions"
expand-text="yes"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output method="text" indent="yes" />
<xsl:template match="/">
<xsl:variable name="json-xml">
<xsl:apply-templates/>
</xsl:variable>
<xsl:value-of select="xml-to-json($json-xml, map { 'indent' : true() })"/>
</xsl:template>
<xsl:template match="method">
<map>
<string key="title">{normalize-space(desc_signature/desc_name)}</string>
<array key="elements">
<xsl:apply-templates select="desc_content/(paragraph | literal_block)"/>
</array>
</map>
</xsl:template>
<xsl:template match="desc_content/*">
<string>{.}</string>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/pNmC4HJ/1

Related

Datatype map: Query array values using "for-each"

I am looking to extract values from an array where each array is connected to a object key name.
The problem I encounter is not knowing how to structure the inner "xsl:foreach" toward a map array.
I will later differentiate the elements by adding attributes but I left that out to keep the question and data at minimal level.
JSON:
<data>
{
"datasheets": {
"balance": {
"cash": [4, 2, 3, 1],
"bank": [5, 8, 7, 9]
}
}
}
</data>
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:docroot="http://www.example.org/1"
xmlns:report="http://www.example.org/2"
xmlns:cells="http://www.example.org/3"
expand-text="yes"
>
<xsl:output method="xml" indent="yes"/>
<xsl:mode on-no-match="shallow-skip"/>
<!-- Parse JSON to XML -->
<xsl:template match="data">
<docroot>
<xsl:apply-templates select="json-to-xml(.)/*"/>
</docroot>
</xsl:template>
<!-- Transform balance data -->
<xsl:template match="*[#key = 'balance']">
<report:yearly-values>
<xsl:for-each select="./*">
<!-- <xsl:for-each select="./*"> -->
<xsl:element name="cells:{#key}">Placeholder</xsl:element>
<!-- </xsl:for-each> -->
</xsl:for-each>
</report:yearly-values>
</xsl:template>
</xsl:transform>
Result:
<?xml version="1.0" encoding="UTF-8"?>
<docroot xmlns:cells="http://www.example.org/3"
xmlns:docroot="http://www.example.org/1"
xmlns:report="http://www.example.org/2">
<report:yearly-values>
<cells:cash>Placeholder</cells:cash>
<cells:bank>Placeholder</cells:bank>
</report:yearly-values>
</docroot>
Wanted result:
<?xml version="1.0" encoding="UTF-8"?>
<docroot xmlns:cells="http://www.example.org/3"
xmlns:docroot="http://www.example.org/1"
xmlns:report="http://www.example.org/2">
<report:yearly-values>
<cells:cash>4</cells:cash>
<cells:cash>2</cells:cash>
<cells:cash>3</cells:cash>
<cells:cash>1</cells:cash>
<cells:bank>5</cells:bank>
<cells:bank>8</cells:bank>
<cells:bank>7</cells:bank>
<cells:bank>9</cells:bank>
</report:yearly-values>
</docroot>
When you first take this debugging step to see what is going on:
<xsl:template match="*[#key = 'balance']">
<report:yearly-values>
<xsl:copy-of select="."/>
</report:yearly-values>
</xsl:template>
Would give this xml-fragment:
<report:yearly-values>
<map xmlns="http://www.w3.org/2005/xpath-functions" key="balance">
<array key="cash">
<number>4</number>
<number>2</number>
<number>3</number>
<number>1</number>
</array>
<array key="bank">
<number>5</number>
<number>8</number>
<number>7</number>
<number>9</number>
</array>
</map>
</report:yearly-values>
Then it is more clear what you need. Take the for-each one level deeper and use the #key of the parent for you element-name, like this:
<xsl:template match="*[#key = 'balance']">
<report:yearly-values>
<xsl:for-each select="*/*">
<xsl:element name="cells:{parent::*/#key}"><xsl:value-of select="text()"/></xsl:element>
</xsl:for-each>
</report:yearly-values>
</xsl:template>
You're just iterating over the two arrays but not the content of the arrays. The following will produce the wanted output:
<xsl:for-each select="./*/*">
<!-- <xsl:for-each select="./*/*"> -->
<xsl:element name="cells:{parent::*/#key}">
<xsl:value-of select="."/>
</xsl:element>
<!-- </xsl:for-each> -->
</xsl:for-each>

Is there any way to remove root nodes after converting XML to JSON using XSLT transformation

I have a requirement, where I have to send data from SAP to API. For this I need to convert XML to JSON format.I am new to XSLT. I have tried converting XML to JSON using XSLT Transformation. After converting, output should not contain Root nodes. And also is there a way of converting output JSON to x-www-form-urlencoded JSON.
Input Data :
<?xml version="1.0" encoding="UTF-8"?>
<ns0:MT_Sales xmlns:ns0="urn:SD:Sales">
<RequestData>
<DODate>2020-02-10</DODate>
<DONumber>1900200009</DONumber>
<OrderNumber>3900002600</OrderNumber>
</RequestData>
<RequestData>
<DODate>2020-02-11</DODate>
<DONumber>1900200010</DONumber>
<OrderNumber>3900002603</OrderNumber>
</RequestData>
<RequestData>
<DODate>2020-02-11</DODate>
<DONumber>1900200011</DONumber>
<OrderNumber>3900002604</OrderNumber>
</RequestData>
</ns0:MT_Sales>
I have used below XSLT coding :
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">{
<xsl:apply-templates select="*"/>}
</xsl:template>
<!-- Object or Element Property-->
<xsl:template match="*">
"<xsl:value-of select="name()"/>" : <xsl:call-template name="Properties"/>
</xsl:template>
<!-- Array Element -->
<xsl:template match="*" mode="ArrayElement">
<xsl:call-template name="Properties"/>
</xsl:template>
<!-- Object Properties -->
<xsl:template name="Properties">
<xsl:variable name="childName" select="name(*[1])"/>
<xsl:choose>
<xsl:when test="not(*|#*)">"<xsl:value-of select="."/>"</xsl:when>
<xsl:when test="count(*[name()=$childName]) > 1">{ "<xsl:value-of select="$childName"/>" :[<xsl:apply-templates select="*" mode="ArrayElement"/>] }</xsl:when>
<xsl:otherwise>{
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="*"/>
}</xsl:otherwise>
</xsl:choose>
<xsl:if test="following-sibling::*">,</xsl:if>
</xsl:template>
<!-- Attribute Property -->
<xsl:template match="#*">"<xsl:value-of select="name()"/>" : "<xsl:value-of select="."/>",
</xsl:template>
</xsl:stylesheet>
Output I received :
{
"ns0:MT_SAP_SecondarySales" : { "RequestData" :[{
"DODate" : "2020-02-10",
"DONumber" : "1900200009",
"OrderNumber" : "3900002600"
},{
"DODate" : "2020-02-11",
"DONumber" : "1900200011",
"OrderNumber" : "3900002604"
}] }}
Output I need:
{"RequestData":[{
"DODate" : "2020-02-10",
"DONumber" : "1900200009",
"OrderNumber" : "3900002600"
},{
"DODate" : "2020-02-11",
"DONumber" : "1900200011",
"OrderNumber" : "3900002604"
}] } ```
Help is much appreciated.
It's easier to write a specific stylesheet that fits your structure than adapt a generic one:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/*">
<xsl:text>{"RequestData":[</xsl:text>
<xsl:for-each select="*">
<xsl:text>{
</xsl:text>
<xsl:for-each select="*">
<xsl:text> "</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>" : "</xsl:text>
<xsl:value-of select="."/>
<xsl:text>"</xsl:text>
<xsl:if test="position()!=last()">,</xsl:if>
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:text>}</xsl:text>
<xsl:if test="position()!=last()">,</xsl:if>
</xsl:for-each>
<xsl:text>]}</xsl:text>
</xsl:template>
</xsl:stylesheet>
All the whitespace characters ( ,
) are of course optional.

XSLT Property name manipulation

I have an XML file that I would like to convert it to JSON with using XSLT. And I would like to manipulate property names of output JSON inside XSLT. But I could not manage to do that. Here is what I tried...
I have following XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="xslt-trial.xsl"?>
<Invoice
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:AccountingCost>Cost Center</cbc:AccountingCost>
<cbc:BuyerReference>Buyer reference</cbc:BuyerReference>
<cac:InvoicePeriod>
<cbc:StartDate>2020-02-11</cbc:StartDate>
<cbc:EndDate>2020-02-21</cbc:EndDate>
</cac:InvoicePeriod>
<cac:ContractDocumentReference>
<cbc:ID>Agreement Id</cbc:ID>
</cac:ContractDocumentReference>
</Invoice>
and "xslt-trial.xsl" is:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">{
<xsl:apply-templates select="*"/>}
</xsl:template>
<!-- Object or Element Property-->
<xsl:template match="*">
"<xsl:value-of select="name()"/>" :<xsl:call-template name="Properties">
<xsl:with-param name="parent" select="'Yes'"> </xsl:with-param>
</xsl:call-template>
</xsl:template>
<!-- Array Element -->
<xsl:template match="*" mode="ArrayElement">
<xsl:call-template name="Properties"/>
</xsl:template>
<!-- Object Properties -->
<xsl:template name="Properties">
<xsl:param name="parent"></xsl:param>
<xsl:variable name="childName" select="name(*[1])"/>
<xsl:choose>
<xsl:when test="not(*|#*)"><xsl:choose><xsl:when test="$parent='Yes'"> <xsl:text>"</xsl:text><xsl:value-of select="."/><xsl:text>"</xsl:text></xsl:when>
<xsl:otherwise>"<xsl:value-of select="name()"/>":"<xsl:value-of select="."/>"</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="count(*[name()=$childName]) > 1">{ "<xsl:value-of select="$childName"/>" :[<xsl:apply-templates select="*" mode="ArrayElement"/>] }</xsl:when>
<xsl:otherwise>{
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="*"/>
}</xsl:otherwise>
</xsl:choose>
<xsl:if test="following-sibling::*">,</xsl:if>
</xsl:template>
<!-- Attribute Property -->
<xsl:template match="#*">"<xsl:value-of select="name()"/>" : "<xsl:value-of select="."/>",
</xsl:template>
</xsl:stylesheet>
I get this output from Edge browser:
{
"Invoice" :{
"cbc:AccountingCost" :"Cost Center",
"cbc:BuyerReference" :"Buyer reference",
"cac:InvoicePeriod" :{
"cbc:StartDate" :"2020-02-11",
"cbc:EndDate" :"2020-02-21"
},
"cac:ContractDocumentReference" :{
"cbc:ID" :"Agreement Id"
}
}}
What I want to get is:
{
"Invoice" :{
"AccountingCost" :"Cost Center",
"BuyerReference" :"Buyer reference",
"InvoicePeriod" :{
"StartDate" :"2020-02-11",
"EndDate" :"2020-02-21"
},
"ContractDocumentReference" :{
"ID" :"Agreement Id"
}
}}
As you can see, I would like to remove "cac:" and "cbc:" from property names. But I cannot manage to filter these values out.
Does anybody have a suggestion?
If you use the function local-name() instead of the function name() then you should get element names without prefixes.

XML to JSON (Webhooks slack)

I would like to convert an XML to JSON using xslt transformation.The purpose is to POST into my slack channel using Incoming Webhooks.
XML File :
<?xml version="1.0" encoding="UTF-8" ?>
<Asset version="1.0">
<Process>
<Date>2017-01-24 14:47:35</Date>
<Status>Success</Status
> <Profile>TEST</Profile>
<Station>DESKTOP</Station>
<User>Système</User>
<Application>APP</Application>
</Process>
<Source>
</Source>
<Target>
<Name>Hello.mp4</Name>
</Target>
</Asset>
I tried this :
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="txt" omit-xml-declaration="yes" encoding="UTF-8"/>
<xsl:template match="/">
{
"text":"<xsl:value-of select="Asset/Process/Profile"/>",
"text":"<xsl:value-of select="Asset/Process/Date"/>",
"text":"<xsl:value-of select="Asset/Target/Name"/>",
"text":"<xsl:value-of select="Asset/Process/Status"/>",
}
</xsl:template>
</xsl:stylesheet>
But i've got this error : 500 - missing_text_or_fallback_or_attachments
Do you have any idea ?
I need to have an JSON like this :
{ "text": "Date: 2017-01-24 14:47:35\n Status: Success\n Profile: TEST\n Station: DESKTOP\n User: Système\n Application: APP"}
https://api.slack.com/incoming-webhooks#sending_messages
Here is the XSLT which produces the desired JSON String:
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text" omit-xml-declaration="yes" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:text>{ "text": "</xsl:text>
<xsl:for-each select="Asset/Process/*">
<xsl:choose>
<xsl:when test="position()=1">
<xsl:value-of select="concat(local-name(),': ',.,'\n')"/>
</xsl:when>
<xsl:when test="position()=last()">
<xsl:value-of select="concat(' ',local-name(),': ',.)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(' ',local-name(),': ',.,'\n')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:text>"}</xsl:text>
</xsl:template>
</xsl:stylesheet>

Converting an RSS pubDate to a mySQL time stamp format using XSLT

I've got a little tool which strips out and re-arranges an iTunes formatted RSS feed and converts it to a nice simple XML file.
I then import the cleansed XML into mySQL to do things with later.
I need to be able to convert the pubDate in the feed to a mySQL timestamp so I can import this properly into a TIMESTAMP field in my table.
I'm having some issues with it.
My current XSL file does a tidy up on the date, but I don't need this at all.
I just want the <pubDate> node to have the correct mySQL friendly timestamp inside instead.
I've not yet managed to find anything which does what I need. Any pointers?
Here is my XSLT file...
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:cc="http://web.resource.org/cc/"
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
xmlns:libsyn="http://libsyn.com/rss-extension"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
exclude-result-prefixes="atom cc itunes libsyn media rdf">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<data>
<entries>
<xsl:apply-templates select="rss/channel/item"></xsl:apply-templates>
</entries>
</data>
</xsl:template>
<xsl:template match="item">
<entry>
<title><xsl:value-of select="title"/></title>
<link><xsl:value-of select="link"/></link>
<description><xsl:value-of select="description" disable-output-escaping="yes"/></description>
<subtitle><xsl:value-of select="itunes:subtitle"/></subtitle>
<pubDate><xsl:value-of select="pubDate"/></pubDate>
<xsl:apply-templates select="pubDate"/>
<explicit><xsl:value-of select="itunes:explicit"/></explicit>
<podcastImage><xsl:value-of select="itunes:image/#href"/></podcastImage>
<podcastURL><xsl:value-of select="enclosure/#url"/></podcastURL>
<podcastLength><xsl:value-of select="enclosure/#length"/></podcastLength>
<podcastDuration><xsl:value-of select="itunes:duration"/></podcastDuration>
</entry>
</xsl:template>
<xsl:template match="pubDate">
<date>
<xsl:attribute name="time"><xsl:value-of select="substring(text(),18,5)"/></xsl:attribute>
<xsl:call-template name="format-from-rfc-to-iso">
<xsl:with-param name="rfc-date" select="text()"/>
</xsl:call-template>
</date>
</xsl:template>
<xsl:template name="format-from-rfc-to-iso">
<xsl:param name="rfc-date"/>
<xsl:param name="day-with-zero" select="format-number(substring(substring($rfc-date,6,11),1,2),'00')"/>
<xsl:param name="month-with-zero">
<xsl:if test="contains($rfc-date,'Jan')">01</xsl:if>
<xsl:if test="contains($rfc-date,'Feb')">02</xsl:if>
<xsl:if test="contains($rfc-date,'Mar')">03</xsl:if>
<xsl:if test="contains($rfc-date,'Apr')">04</xsl:if>
<xsl:if test="contains($rfc-date,'May')">05</xsl:if>
<xsl:if test="contains($rfc-date,'Jun')">06</xsl:if>
<xsl:if test="contains($rfc-date,'Jul')">07</xsl:if>
<xsl:if test="contains($rfc-date,'Aug')">08</xsl:if>
<xsl:if test="contains($rfc-date,'Sep')">09</xsl:if>
<xsl:if test="contains($rfc-date,'Oct')">10</xsl:if>
<xsl:if test="contains($rfc-date,'Nov')">11</xsl:if>
<xsl:if test="contains($rfc-date,'Dec')">12</xsl:if>
</xsl:param>
<xsl:param name="year-full" select="format-number(substring(substring($rfc-date,6,11),7,5),'####')"/>
<xsl:param name="rfc-date-to-iso" select="concat($year-full,'-',$month-with-zero,'-',$day-with-zero)"/>
<xsl:value-of select="$rfc-date-to-iso"/>
</xsl:template>
</xsl:stylesheet>
The current date/time looks like this from the rss feed:
<pubDate>Sun, 07 Feb 2016 00:00:56 -0500</pubDate>
I'd like it to by displayed like this so it can be inserted into mySQL:
<pubDate>2016-02-07 00:00:56</pubDate>
I use PHP to process this.
$xml = new DOMDocument;
$xml->load('podbean.xml');
$xsl = new DOMDocument;
$xsl->load('podbean.xsl');
// Configure the transformer
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl); // attach the xsl rules
$proc->transformToXML($xml);
$proc->transformToURI($xml,'itunes.xml');
Simon
Using a processor that supports the EXSLT str:tokenize() function (as libxslt does), you can do something like this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- ... -->
<xsl:template match="item">
<entry>
<!-- ... -->
<pubDate>
<xsl:variable name="date-tokens" select="str:tokenize(pubDate, ' ' )" />
<!-- year -->
<xsl:value-of select="$date-tokens[4]" />
<xsl:text>-</xsl:text>
<!-- month -->
<xsl:variable name="mmm" select="$date-tokens[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>
<!-- day -->
<xsl:value-of select="format-number($date-tokens[2], '00')" />
<xsl:text> </xsl:text>
<!-- time -->
<xsl:value-of select="$date-tokens[5]" />
</pubDate>
<!-- ... -->
</entry>
</xsl:template>
</xsl:stylesheet>