0

Below XSLT converts First character of each word to upper case.But Fails for special case (example:for input-> the 'lion ,king output is-> The 'Lion ,King). Need solution for the special case also.

<xsl:template name="Split">
    <xsl:param name="pText"/>
    <xsl:if test="string-length($pText)">
        <xsl:variable name="vConvertedWord" select="concat(translate(substring(substring-before(concat($pText,$vSeparator),$vSeparator),1,1), $smallcase,$uppercase),substring(substring-before(concat($pText,$vSeparator),$vSeparator),2))"/>      
                    <xsl:value-of select="$vConvertedWord"/>

        <xsl:value-of select="$vSeparator"/>
        <xsl:call-template name="Split">
            <xsl:with-param name="pText" select="substring-after($pText,$vSeparator)"/>
        </xsl:call-template>

</xsl:template>
  • It was not possible to reproduce your problem. Either there is not enough information or the data you provided is incorrect. See: http://xsltransform.net/6qVRKvH . Edit your question and include sufficient information that will allow the problem to be diagnosed. – helderdarocha Jun 24 '14 at 15:23
  • @helderdarocha I would guess the separator is a space? – michael.hor257k Jun 24 '14 at 18:03
  • @michael.hor257k It probably is. – helderdarocha Jun 24 '14 at 18:14
  • 1
    In addition to posting a **complete** stylesheet (where all your variables are defined), you need to clarify what exactly a "special case" is and how it needs to be treated. There are many possible variations here, e.g. "The ,king ?king !@#king 2king éking ..." to mention just a few. Note that XSLT 1.0 has no concept of a "word", and you will need to get quite explicit in enumerating the possible cases - with a considerable likelihood of an unexpected scenario slipping through the net. – michael.hor257k Jun 24 '14 at 19:09

1 Answers1

0

I think what you are asking is that you may have multiple separators, not just a space, but a comma too? And also maybe you want some 'small' words not to be capitalised?

Just for my own personal challenge, the solution I came up with is to iterate over the text one character at a time, building up a 'word' until you reach a 'separator'. You can then capitalise the word you have built up, unless it happens to be a 'small' word. You then continue iterating with a new empty word to be built up.

Try this XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:variable name="smallcase">abcdefghijklmnopqrstuvwxyz</xsl:variable>
    <xsl:variable name="uppercase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
    <xsl:variable name="vSeparator"> ,.</xsl:variable>
    <xsl:variable name="vProp"> a an the and </xsl:variable>

    <xsl:template match="text()">
        <xsl:call-template name="Split">
            <xsl:with-param name="pText" select="." />
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="Split">
        <xsl:param name="pText"/>
        <xsl:param name="letterPos" select="1" />
        <xsl:param name="currentWord" select="''" />

        <xsl:variable name="nextChar" select="translate(substring($pText, $letterPos, 1), $uppercase ,$smallcase)" />
        <xsl:variable name="separatorFound" select="($nextChar = '' or contains($vSeparator, $nextChar))" />

        <xsl:if test="$separatorFound">
            <xsl:choose>
                <xsl:when test="contains($vProp, concat(' ', $currentWord, ' ')) and $letterPos &gt; string-length($currentWord) + 1">
                    <xsl:value-of select="$currentWord" />
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="translate(substring($currentWord, 1, 1), $smallcase ,$uppercase)" />
                    <xsl:value-of select="substring($currentWord, 2, string-length($currentWord) - 1)" />
                </xsl:otherwise>
            </xsl:choose>
            <xsl:value-of select="$nextChar" />
        </xsl:if>

        <xsl:variable name="newWord">
            <xsl:if test="not($separatorFound)"><xsl:value-of select="concat($currentWord, $nextChar)"/></xsl:if>
        </xsl:variable>

        <xsl:if test="$letterPos &lt;= string-length($pText)">
            <xsl:call-template name="Split">
                <xsl:with-param name="pText" select="$pText" />
                <xsl:with-param name="letterPos" select="$letterPos + 1" />
                <xsl:with-param name="currentWord" select="$newWord" />
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

When applied to this XML

<text>The Lion king, the tiger queen and the hippo prince</text>

The following is output

The Lion King, the Tiger Queen and the Hippo Prince

EDIT - Alternate solution

If you want to capitalise letters that occur after , or ., then try this XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:variable name="smallcase">abcdefghijklmnopqrstuvwxyz</xsl:variable>
    <xsl:variable name="uppercase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
    <xsl:variable name="vSeparator">,.</xsl:variable>
    <xsl:variable name="vProp"> a an the and </xsl:variable>

    <xsl:template match="text()">
        <xsl:call-template name="Split">
            <xsl:with-param name="pText" select="." />
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="Split">
        <xsl:param name="pText"/>
        <xsl:param name="letterPos" select="1" />
        <xsl:param name="currentWord" select="''" />
        <xsl:param name="startOfBlock" select="1" />

        <xsl:variable name="nextChar" select="translate(substring($pText, $letterPos, 1), $uppercase ,$smallcase)" />
        <xsl:variable name="separatorFound" select="($nextChar = '' or $nextChar = ' ' or contains($vSeparator, $nextChar))" />

        <xsl:if test="$separatorFound">
            <xsl:choose>
                <xsl:when test="contains($vProp, concat(' ', $currentWord, ' ')) and $startOfBlock = 0">
                    <xsl:value-of select="$currentWord" />
                </xsl:when>
                <xsl:otherwise>
                <xsl:value-of select="translate(substring($currentWord, 1, 1), $smallcase ,$uppercase)" />
                    <xsl:value-of select="substring($currentWord, 2, string-length($currentWord) - 1)" />
                </xsl:otherwise>
            </xsl:choose>
            <xsl:value-of select="$nextChar" />
        </xsl:if>

        <xsl:variable name="newWord">
            <xsl:if test="not($separatorFound)"><xsl:value-of select="concat($currentWord, $nextChar)"/></xsl:if>
        </xsl:variable>

        <xsl:variable name="newStartOfBlock">
            <xsl:choose>
                <xsl:when test="contains($vSeparator, $nextChar)"><xsl:value-of select="1" /></xsl:when>
                <xsl:when test="$nextChar = ' ' and $currentWord != ''"><xsl:value-of select="0" /></xsl:when>
                <xsl:otherwise><xsl:value-of select="$startOfBlock" /></xsl:otherwise>
            </xsl:choose>
        </xsl:variable>

        <xsl:if test="$letterPos &lt;= string-length($pText)">
            <xsl:call-template name="Split">
                <xsl:with-param name="pText" select="$pText" />
                <xsl:with-param name="letterPos" select="$letterPos + 1" />
                <xsl:with-param name="currentWord" select="$newWord" />
                <xsl:with-param name="startOfBlock" select="$newStartOfBlock" />
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

When applied to this XML

<text>The Lion king, the tiger queen and the hippo prince.... And cats, bats and rats.</text>

The following is output:

The Lion King, The Tiger Queen and the Hippo Prince.... And Cats, Bats and Rats.
Tim C
  • 70,053
  • 14
  • 74
  • 93