0

I am quite new to xsl and functional programming, so I'll be grateful for help on this one:

I have a template that transforms some xml and provides an output. The problem is that there are many elements of type xs:date, all in different contexts, that must be localized. I use a concatenation of substrings of these xs:dates to produce a localized date pattern strings.

As you can guess this causes a lot of copy-paste "substring-this and substring-that". How can I write a template that will automatically transform all the elements of type xs:date to localized strings preserving all the context-aware transformations?

My xsl is something like this:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">  
    <xsl:output method="html" encoding="utf-8"/>
        <xsl:template match="/">
        ...
        <input value="{substring(/select/a/date 9,2)}.{substring(/select/a/date, 6,2)}.{substring(/select/a/date 1,4)}">
        ...
        <!-- assume that following examples are also with substrings -->
        <div><xsl:value-of select="different-path/to_date"/></div>
        ...
        <table>
        <tr><td><xsl:value-of select="path/to/another/date"/></td></tr>
        </table>
        <apply-templates/>
        </xsl:template>
        <xsl:template match="something else">
        <!-- more dates here -->
        </xsl:template>
</xsl:stylesheet>

I hope I managed to make my question clear =)

UPD: Here is an example of xml:

<REQUEST>
    <header>
        <... />
        <ref>
            <ref_date type="xs:date">1970-01-01</ref_date>
        </ref>
    </header>

    <general>
        <.../>
        <info>
            <.../>
            <date type="xs:date">1970-01-01</date>
            <ExpireDate type="xs:date">1970-01-01</ExpireDate>
            <RealDate type="xs:date">1970-01-01</RealDate>
            <templateDetails>template details</templateDetails>
            <effectiveDate type="xs:date">1970-01-01</effectiveDate>
        </info>

        <party>
            <.../>
                <date type="xs:date">1970-01-01</date>
        </party>

        <!-- many other parts of such kind -->
    </general>

</REQUEST>

As for the output, there are many different options. The main thing is that these values must be set as a value of different html objects, such as tables, input fields and so on. You can see an example in the xsl listing.

P.S. I'm using xsl 1.0.

svz
  • 4,516
  • 11
  • 40
  • 66
  • 1
    This could almost certainly be achieved by making use of a single template in your XSLT, but it would really helpful if you showed a (small) sample XML document, and your expected output. Thanks! – Tim C Sep 12 '12 at 13:03
  • Please, also provide the exact wanted output. – Dimitre Novatchev Sep 12 '12 at 13:22
  • @Dimitre Novatchev, do you really want me to post 45kB of html here? =) – svz Sep 12 '12 at 13:32
  • @svz, No, but one can always provide a *small* and complete example of their problem. Just about dozen lines or so. – Dimitre Novatchev Sep 12 '12 at 13:37
  • @Dimitre Novatchev, there are three small and complete examples in the xsl listing. Assume there are hundreds of small blocks of code of that kind. All on different levels of xpath. Anyway, this is not getting constructive. – svz Sep 12 '12 at 13:43

2 Answers2

2

If you did a schema-aware XSLT 2.0 transformation, you wouldn't need all those type='xs:date' attributes: defining it in the schema as a date would be enough. You could then match the attributes with

<xsl:template match="attribute(*, xs:date)">

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
1

What you could do is add a template to match any element which has an @type attribute of 'xs:date', and do you substring manipulation in there

<xsl:template match="*[@type='xs:date']">
   <xsl:value-of select="translate(., '-', '/')" />
</xsl:template>

In this case I am just replacing the hyphens by slashes as an example.

Then, instead of using xsl:value-of....

<div><xsl:value-of select="different-path/to_date"/></div>  

You could use xsl:apply-templates

<div><xsl:apply-templates select="different-path/to_date"/></div>  

Consider this XSLT as an example

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">        
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="*[@type='xs:date']">
        <xsl:copy>
            <xsl:value-of select="translate(., '-', '/')" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

In this case, all this XSLT is doing is copying the XML document as-is, but changing the date elements.

If you wanted to use the date template for other elements, or values, you could also make it a named-template, like so

<xsl:template match="*[@type='xs:date']" name="date">
    <xsl:param name="date" select="." />
    <xsl:value-of select="translate($date, '-', '/')" />
</xsl:template>

This would allow you to also call it much like a function. For example, to format a data and add as an attribute you could do the following:

<input>
   <xsl:attribute name="value">
       <xsl:call-template name="date">
          <xsl:with-param name="date" select="/select/a/date" />
       </xsl:call-template>
   </xsl:attribute>
</input>
Tim C
  • 70,053
  • 14
  • 74
  • 93
  • Yes, this looks like what I need, thanks. I'll give it a try. Btw, how do I use `` in such case: ``? Do I have to use `` and xml escaping to ensure the `` tag is processed correctly or is there any other way? – svz Sep 12 '12 at 13:36
  • I've expanded my answer to explain this a bit more. – Tim C Sep 12 '12 at 13:40
  • Thanks! Wish I could +1 twice =) – svz Sep 12 '12 at 13:44