transforming dates from yyyy-mm-dd to dd/mm/yyyy catering for null or empty dates in xslt
I wanted to change the order of dates from yyyy-mm-dd to 开发者_Go百科dd/mm/yyyy but cater for null or empty dates I used the code
<!-- Data Submitted -->
<xsl:template match="data_submitted">
<data_submitted>
<xsl:if test="data_submitted != ''">
<xsl:value-of select=
"concat(substring(.,9), '/',
(substring(.,6,2)), '/',
substring(.,1,4))"
/>
</xsl:if>
</data_submitted>
</xsl:template>
<!-- -->
but this omitted dates altogether. Leaving out the resulted in the null dates appearing as // in my result. I'm sure I have probably got the if in the wrong place or something, but I want a tag to appear even if it is empty.
Any suggestions?
Update:
Apologies everyone, I should have given the initial xml as I was testing for null or empty and there were actually spaces in the element, so my initial translation would have worked if I just put in the number of spaces. The original xml is: data_submitted> </data_submitted>
with 8 spaces.
test="data_submitted != ' '"
is what was required or:
test=".!= ''"
, each with 8 spaces.
You haven't explained what you mean by "null or empty". Your template should work if the data_submitted element exists and has no content, but it won't work if the data_submitted element doesn't exist. To handle both non-existence and emptiness, replace data_submitted != ''
by not(data_submitted = '')
. In fact, as a general rule, don't use "!=" in XSLT unless you are an expert and know exactly what it means.
There a "tiny" mistake..Compare with this (corrected) transform if you get it:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="data_submitted">
<data_submitted>
<xsl:variable name="year" select="substring-before(.,'-')"/>
<xsl:variable name="month" select="substring-before(substring-after(.,'-'),'-')"/>
<xsl:variable name="day" select="substring-after(substring-after(.,'-'),'-')"/>
<xsl:if test=".!=''">
<xsl:value-of select=
"concat($day,'/',
$month,'/',
$year)"
/>
</xsl:if>
</data_submitted>
</xsl:template>
</xsl:stylesheet>
Applied on this sample input:
<data>
<data_submitted>
yyyy-mm-dd
</data_submitted>
<data_submitted/>
</data>
Returns:
<data>
<data_submitted>dd/mm/yyyy</data_submitted>
<data_submitted/>
</data>
Got the mistake?
The template is already in the context of the data_submitted
, so inside the template test you just need .
to refer to the matched element.
However, I suggest you to test empty text()
nodes in the template context above as follows:
test="boolean(./text())"
or (the same in your context)
test="boolean(text())"
This will return false if, and only if, the text string length is 0
.
Your mistake is testing if any data_submitted
child of the current (data_submitted
) node has a non-empty string value. I guess that the data_submitted
elements in the source XML document dont have any data_submitted
children at all.
Here is a complete and short solution of your problem, just overriding the identity rule/template:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="data_submitted/text()">
<xsl:value-of select=
"concat(substring(.,9),
'/',
substring(.,6,2),
'/',
substring(.,1,4)
)
"/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied to the following XML document:
<t>
<a/>
<b>
<data_submitted>2011-06-07</data_submitted>
<data_submitted/>
</b>
<data_submitted>1912-05-12</data_submitted>
<c/>
</t>
the wanted, correct result is produced:
<t>
<a/>
<b>
<data_submitted>07/06/2011</data_submitted>
<data_submitted/>
</b>
<data_submitted>12/05/1912</data_submitted>
<c/>
</t>
Explanation:
The identity template copies every node "as-is"
A single template is overriding the identity rule -- for the text-node children of any
data_submitted
element. The code here produces the wanted transformed date. All other nodes, even including emptydata_submitted
elements are processed by the identity rule and are copied "as-is" to the output.
Remember: In many cases it isn't necessary to use any XSLT conditional instructions.
Use the power of XSLT templates and pattern-matching.
Generally when testing if a node exists, you put the xpath expression in your "test" statement. Without seeing your xml, I would guess that you can simply remove the "!= ''" and you should be fine.
精彩评论