开发者

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:

  1. The identity template copies every node "as-is"

  2. 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 empty data_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.


0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜