views:

3870

answers:

2

Hello,

If have a following element in my XSL file:

<xsl:value-of select="replace(lower-case(@name), '_([a-z0-9])', '$1')" />

For example from 'get_polygene_lubricants' it makes 'getpolygenelubricants'.

What I want to do is to replace the first letter after '_' with the uppercase variant of the letter. I googled, read documentation, but I was not able to found any solution in XSLT for that simple replacement.

Maybe somebody knows whether it is possible in XSLT 2.0?

+1  A: 

You could do this using a template, recursively calling itself to iterate through the characters in the string. This template should take a position parameter, starting at 1 and increasing for each call to the template. When '_' is found, transform next char to upper case using translate(1.0) or upper-case(2.0)

baretta
I created such a monster 21 lines of xml instead of 1. But importantly it works. :) Thanks for the hint.
Jagger
Yea it's not very delicate, i would agree on that. I tend to include these hacks from some common XSLT file, so i don't have to see them.
baretta
With XPath 2.0 / XSLT 2.0 there is a more straightforward solution and it does not require recursion. So, probably it is more efficient, too. See my solution.
Dimitre Novatchev
+1  A: 

Edited: Per clarification from the original poster, the first string delimited by the underscores should not have its starting letter capitalized.

This solution does not use recursion and should be quite more efficient.

Here is the new solution:

string-join(
            (for  $i in 1 to count(tokenize(.,'_')),
                  $s in tokenize(.,'_')[$i],
                  $fl in substring($s,1,1),
                  $tail in substring($s,2)
               return
                  if($i eq 1)
                   then $s
                   else concat(upper-case($fl), $tail)
             ),
                        ''
           )

The result is now exactly as required:

underLinedString

Below is the old solution.

The replace() function supposes that you have a fixed replacement -- therefore it is not the best tool for solving this problem.

Here is a one-liner XPath 2.0 solution (and it certainly can be used as part of an XSLT 2.0 transformation :)     ):

string-join(
            (for $s in tokenize(.,'_'),
                 $fl in substring($s,1,1),
                 $tail in substring($s,2)
               return
                 concat(upper-case($fl), $tail)
             ),
            ''
           )

When we use the above expression in an XSLT 2.0 transformation like this:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
    <xsl:template match="/">
     <xsl:sequence select=
      "string-join(
                (for $s in tokenize(.,'_'),
              $fl in substring($s,1,1),
           $tail in substring($s,2)
            return
       concat(upper-case($fl), $tail)
                ),
             ''
                  )

      "/>
    </xsl:template>
</xsl:stylesheet>

and apply it on this XML document:

<t>under_lined_String</t>

the wanted result is produced:

UnderLinedString
Dimitre Novatchev
Thanks for the example. I do not know XPath 2.0 but from now on for sure I am gonna learn something of it. However your solution is not exactly what I want as the first letter in the result string has to be lower case.
Jagger
@Jagger It is edited and produces your result -- just with a single XPath expression :)
Dimitre Novatchev
@Dimitre Yes, it looks very neat. I switched to your solution. Thank you very much.
Jagger