This version worked for me.  I added a choose that outputs "the rest" of the string when no more underbars are present.
<xsl:variable name="vLower" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="vUpper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:template name="Pascalize">
    <xsl:param name="pText" />
    <xsl:if test="$pText">
        <xsl:value-of select="translate(substring($pText,1,1), $vLower, $vUpper)" />
        <xsl:choose>
            <xsl:when test="contains($pText, '_')"> 
                <xsl:value-of select="substring-before(substring($pText,2), '_')" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="substring($pText,2)" />
            </xsl:otherwise>
        </xsl:choose>
        <xsl:call-template name="Pascalize">
            <xsl:with-param name="pText" select="substring-after(substring($pText,2), '_')" />
        </xsl:call-template>
    </xsl:if>
</xsl:template>
Also, in case anyone comes here looking for the reverse process (which I happened to also require today and could find not a single example of anywhere)...
<xsl:variable name="vLower" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="vUpper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:template name="TitleCase">
    <xsl:param name="pText" />
    <xsl:call-template name="TitleCase_recurse">
        <xsl:with-param name="pText" select="concat(translate(substring($pText,1,1), $vLower, $vUpper), substring($pText,2))" />
    </xsl:call-template>
</xsl:template>
<xsl:template name="TitleCase_recurse">
    <xsl:param name="pText" />
    <xsl:if test="string-length($pText) > 1">
        <xsl:if test="not(substring($pText,1,1) = ' ' and substring($pText,1,1) = ' ')">
            <xsl:value-of select="substring($pText,1,1)" />
        </xsl:if>
        <xsl:if test="translate(substring($pText,1,1), $vLower, $vUpper) != substring($pText,1,1)">
            <xsl:if test="translate(substring($pText,2,1), $vLower, $vUpper) = substring($pText,2,1)">
                <xsl:text> </xsl:text>
            </xsl:if>
        </xsl:if>
        <xsl:call-template name="TitleCase_recurse">
            <xsl:with-param name="pText" select="substring($pText,2)" />
        </xsl:call-template>
    </xsl:if>
    <xsl:if test="string-length($pText) = 1">
        <xsl:value-of select="$pText" />
    </xsl:if>
</xsl:template>
I love it when my subconscious brain pops up an answer a few hours after I've completely given up consciously. ;-)