SharePoint XSLT Problem - - sharepoint

I am trying to do some highlighting on some SharePoint XSLT Results. BElow is the XML that i am getting.
The Problem that i am getting is that the Template Match blocks are not matching the child nodes of UM If someone can see where i am going wrong that woould be great.
Thank you
Chhris
<rows>
<row>
<LastModifiedTime>02/25/2010 18:32:25</LastModifiedTime>
<RANK>325</RANK>
<TITLE>UMUK Win At The Mobile Entertainment</TITLE>
<AUTHOR>SVR08-002\Administrator</AUTHOR>
<CREATED>02/25/2010 18:32:22</CREATED>
<PATH>http://svr08-002:7005/Lists/FrontPageNews/DispForm.aspx?ID=3</PATH>
<HitHighlightedSummary>a
<c0>UM</c0> UK won the category of Best Music Label 2009 at the 4th annual ME (Mobile Entertainment) Awards C <ddd/>
</HitHighlightedSummary>
</row>
</rows>
and here is the XSLT that i have so far.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:template match="/">
<table class="ICS_SearchTable" cellpadding="0" cellspacing="0" width="100%">
<xsl:for-each select="rows/row">
<xsl:variable name="Ext">
<xsl:call-template name="get-file-extension">
<xsl:with-param name="path" select="substring-before(PATH, '?')" />
</xsl:call-template>
</xsl:variable>
<tr>
<td width="10%">
</td>
<td>
<div class="ICS_SearchResultItem">
<div class="ICS_SearchResultItemImage">
<img src="/Style Library/UMIGlobe/Styles/Images/Common/umgi-{$Ext}.png" alt="{$Ext}"/>
</div>
<div class="ICS_SearchResultItemTitle">
<xsl:value-of select="TITLE"/>
</div>
<div class="ICS_SearchResultItemDesc">
<xsl:choose>
<xsl:when test="HitHighlightedSummary[. != '']">
<xsl:call-template name="HitHighlighting">
<xsl:with-param name="hh" select="HitHighlightedSummary" />
</xsl:call-template>
</xsl:when>
<xsl:when test="DESCRIPTION[. != '']">
<xsl:value-of select="DESCRIPTION"/>
</xsl:when>
</xsl:choose>
</div>
<div class="ICS_SearchResultItemLink">
<xsl:value-of select="PATH"/> - <xsl:value-of select="AUTHOR" /> - <xsl:value-of select="LastModifiedTime"/>
<xsl:call-template name="DisplaySize">
<xsl:with-param name="size" select="SIZE" />
</xsl:call-template>
</div>
</div>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template name="HitHighlighting">
<xsl:param name="hh" />
<xsl:apply-templates select="$hh"/>
</xsl:template>
<xsl:template match="ddd">
…
</xsl:template>
<xsl:template match="c0">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c1">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c2">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c3">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c4">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c5">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c6">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c7">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c8">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<xsl:template match="c9">
<b>
<xsl:value-of select="."/>
</b>
</xsl:template>
<!-- The size attribute for each result is prepared here -->
<xsl:template name="DisplaySize">
<xsl:param name="size" />
<xsl:if test='string-length($size) > 0'>
<xsl:if test="number($size) > 0">
-
<xsl:choose>
<xsl:when test="round($size div 1024) < 1"><xsl:value-of select="$size" /> Bytes</xsl:when>
<xsl:when test="round($size div (1024 *1024)) < 1"><xsl:value-of select="round($size div 1024)" />KB</xsl:when>
<xsl:otherwise><xsl:value-of select="round($size div (1024 * 1024))"/>MB</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:if>
</xsl:template>
<xsl:template name="get-file-extension">
<xsl:param name="path" />
<xsl:choose>
<xsl:when test="contains( $path, '/' )">
<xsl:call-template name="get-file-extension">
<xsl:with-param name="path" select="substring-after( $path, '/' )" />
</xsl:call-template>
</xsl:when>
<xsl:when test="contains( $path, '.' )">
<xsl:call-template name="get-file-extension">
<xsl:with-param name="path" select="substring-after( $path, '.' )" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- SET THE PATH IMAGE SRC -->
<xsl:choose>
<xsl:when test="$path = 'uk' or $path = 'org' or $path = 'com' or $path = 'net' or $path = 'biz' or $path = 'gov'">
<xsl:text>url</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$path" />
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

What do you mean by "child nodes of UM"?
Maybe I'm missing something, but there are no nodes named "UM", just text. So do you mean that you want to match the node that contains the text "UM"... in other words <c0>UM</c0>?
In my case, when I run your stylesheet, it does match the <c0> node, and writes a <b> node.
<b>UM</b> UK won the category of Best Music Label 2009 at the 4th annual ME (Mobile Entertainment) Awards C
What's not working for you?

Related

XSLT 1.0: Replacing all occurences of a string in a node-set

I have the following function which replaces all occurences of a search-string ($replace) in a string ($text) with another string ($by):
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text"
select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
This works fine for replacing text in individual strings, however it doesn't work when trying to replace text in a node-set.
What I am looking for is a function which takes, for example, the following XML document:
<nodeSet>
<node>a1;a2;a3</node>
<node>b1;b2;b3</node>
</nodeSet>
and outputs the following:
<nodeSet>
<node>a1#a2#a3</node>
<node>b1#b2#b3</node>
</nodeSet>
The following template does the job when the target and replacement strings are known in advance:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl"
>
<xsl:template name="string-replace-all-in-nodeset">
<xsl:param name="nodeset" />
<xsl:apply-templates select="exsl:node-set($nodeset)" mode="str-repl-in-nodeset"/>
</xsl:template>
<xsl:template match="*/text()" mode="str-repl-in-nodeset">
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="replace" select=" ';' "/>
<xsl:with-param name="by" select=" '#' "/>
</xsl:call-template>
</xsl:template>
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="#*|node()" mode="str-repl-in-nodeset">
<xsl:copy>
<xsl:apply-templates select="#*|node()" mode="str-repl-in-nodeset"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
However, I need to be able to pass the target and replacement string (';' and '#' in this case) dynamically. Is there any way of passing these parameters to the template matching all text nodes (match="*/text()") or any other way of achieving what I want?
Here is a stylesheet that defines global parameters for the replace and by strings and then passes them on to all templates in that mode str-repl-in-nodeset:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl">
<xsl:param name="ns1">
<nodeSet>
<node>a1;a2;a3</node>
<node>b1;b2;b3</node>
</nodeSet>
</xsl:param>
<xsl:param name="replace" select="';'"/>
<xsl:param name="by" select="'#'"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="exsl:node-set($ns1)" mode="str-repl-in-nodeset">
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="by" select="$by"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="/ | #* | node()" mode="str-repl-in-nodeset">
<xsl:param name="replace"/>
<xsl:param name="by"/>
<xsl:copy>
<xsl:apply-templates select="#*|node()" mode="str-repl-in-nodeset">
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="by" select="$by"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="*/text()" mode="str-repl-in-nodeset">
<xsl:param name="replace"/>
<xsl:param name="by"/>
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="by" select="$by"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:transform>

Removing asterisks and single quotes from attribute values using XSL

I have this XML fragment:
<svrl:successful-report test="."
location="/*[local-name()='ClinicalDocument']/*[local-name()='component']/*[local-name()='structuredBody']/*[local-name()='component'][1]/*[local-name()='section']">
I want to get the value #location and remove the special characters " *[local-name()=' " and " '] ". In other words, I want the output to be
/ClinicalDocument/component/structuredBody/component[1]/section
I'm currently using this string replace template:
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text"
select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
and applying the template like this
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="#location"/>
<xsl:with-param name="replace" select="'[local-name()='"/>
<xsl:with-param name="by" select="''"/>
</xsl:call-template>
That only gives this result:
/*'ClinicalDocument']/*'component']/*'structuredBody']/*'component'][1]/*'section']
How can I get the output I want?
The other answer to this question is a good one, but has problems with a source XML document like this:
<test xmlns:svrl="my:my">
<svrl:successful-report test="." location=
"/*[local-name()='ClinicalDocument']/*[local-name()='component'][.='abc']"/>
</test>
The result it produces when applied on this document is:
/ClinicalDocument/component[.='abc
But the correct result is:
/ClinicalDocument/component[.='abc']
This transformation has no problems with the above XML document:
<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="#location">
<xsl:attribute name="location">
<xsl:call-template name="makeExplicit">
<xsl:with-param name="pText" select="substring(.,2)"/>
</xsl:call-template>
</xsl:attribute>
</xsl:template>
<xsl:template name="makeExplicit">
<xsl:param name="pText" select="."/>
<xsl:if test="$pText">
<xsl:variable name="vStep" select="substring-before(concat($pText, '/'), '/')"/>
<xsl:call-template name="processStep">
<xsl:with-param name="pStep" select="$vStep"/>
</xsl:call-template>
<xsl:call-template name="makeExplicit">
<xsl:with-param name="pText" select="substring-after($pText, '/')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="processStep">
<xsl:param name="pStep"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="substring-before(concat($pStep, '*['), '*[')"/>
<xsl:variable name="vPred" select="substring-after($pStep, '*[local-name()=')"/>
<xsl:value-of select="substring-before(substring($vPred, 2), "'")"/>
<xsl:value-of select="substring-after($vPred, ']')"/>
</xsl:template>
</xsl:stylesheet>
When applied on the above document, the correct, wanted result is produced:
<test xmlns:svrl="my:my">
<svrl:successful-report test="."
location="/ClinicalDocument/component[.='abc']"/>
</test>
You need to do two 'find and replace' here. Firstly you need to remove all of the prefixes *[local-name()=', and then you need to remove the suffixes of ']
You can do this by passing the results of the first call-template as a parameter to the second call-template
Here is the full XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svrl="my:my">
<xsl:template match="svrl:successful-report">
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text">
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="#location"/>
<xsl:with-param name="replace" select=""*[local-name()='""/>
<xsl:with-param name="by" select="''"/>
</xsl:call-template>
</xsl:with-param>
<xsl:with-param name="replace" select=""']""/>
<xsl:with-param name="by" select="''"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="string-replace-all">
<xsl:param name="text"/>
<xsl:param name="replace"/>
<xsl:param name="by"/>
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)"/>
<xsl:value-of select="$by"/>
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="substring-after($text,$replace)"/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="by" select="$by"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
When applied to the following XML
<test xmlns:svrl="my:my">
<svrl:successful-report test="." location="/*[local-name()='ClinicalDocument']/*[local-name()='component']/*[local-name()='structuredBody']/*[local-name()='component'][1]/*[local-name()='section']"/>
</test>
The following is output
/ClinicalDocument/component/structuredBody/component[1]/section

SharePoint 2010: How do I use the 'onmouseover' attribute in the ItemStyle.XSL file for the Content Query Webpart?

I'm currently working in SharePoint 2010, with the Content Query Webpart.
I just want to show a list, but when the user hovers the mouse over the item, I want him/her to see a description. I have tried to put the 'onmouseover' attribute everywhere, but nothing seems to work.
This is my code so far:
<xsl:variable name="SafeLinkUrl">
<xsl:call-template name="OuterTemplate.GetSafeLink">
<xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="DisplayTitle">
<xsl:call-template name="OuterTemplate.GetTitle">
<xsl:with-param name="Title" select="#Title"/>
<xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="Description">
<xsl:value-of select="#Description" />
</xsl:variable>
<xsl:variable name="Start">
<xsl:value-of select="ddwrt:FormatDateTime(string(#Start), 1033, 'H:mm')" />
</xsl:variable>
<xsl:variable name="End">
<xsl:value-of select="ddwrt:FormatDateTime(string(#End), 1033, 'H:mm')" />
</xsl:variable>
<xsl:variable name="Speaker">
<xsl:value-of select="#Speaker" />
</xsl:variable>
<xsl:variable name="tableStart">
<xsl:if test="$CurPos = 1">
<![CDATA[
<table border=1 bgcolor=#CCFFFF>
<tr>
<td><b>Start</b></td>
<td><b>End</b></td>
<td><b>Title</b></td>
<td><b>Speaker</b></td>
</tr>
]]>
</xsl:if>
</xsl:variable>
<xsl:variable name="tableEnd">
<xsl:if test="$CurPos = $Last">
<![CDATA[ </table> ]]>
</xsl:if>
</xsl:variable>
<xsl:comment>Start of HTML section</xsl:comment>
<xsl:value-of select="$tableStart" disable-output-escaping="yes"/>
<tr>
<td><b> <xsl:value-of select="$Start"/> </b></td>
<td><b> <xsl:value-of select="$End"/> </b></td>
<td style="width:500px"><b> <xsl:value-of select="$DisplayTitle"/></b></td>
<td> <xsl:attribute name="onmouseover"> <xsl:value-of select="#Description"/> </xsl:attribute> </td>
<td><b> <xsl:value-of select="$Speaker"/> </b></td>
</tr>
<xsl:value-of select="$tableEnd" disable-output-escaping="yes"/>
Where do I put the 'onmouseover' attribute so that when your mouse hovers over an item, it shows the description?
Thanks in advance.

MOSS Content Query Web part itemstyle.xsl

I have a Content Query Webpart (CQWP) pulling the URL and title from a News links list. The CQWP uses the XSLT style Orange.News.Links defined in ItemStyle.xsl.
I need to sort the title #Title0 field as commented out below because it causes an error.
Does anyone know whats causing this error? - Many Thanks. The XSLT code is below:
<xsl:template name="Orange.News.Links" match="Row[#Style='Orange.News.Links']" mode="itemstyle">
<xsl:param name="CurPos" />
<xsl:param name="Last" />
<xsl:variable name="SafeLinkUrl">
<xsl:call-template name="OuterTemplate.GetSafeLink">
<xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="DisplayTitle">
<xsl:call-template name="OuterTemplate.GetTitle">
<xsl:with-param name="Title" select="#URL"/>
<xsl:with-param name="UrlColumnName" select="'URL'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="LinkTarget">
<xsl:if test="#OpenInNewWindow = 'True'" >_blank</xsl:if>
</xsl:variable>
<xsl:variable name="SafeImageUrl">
<xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
<xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="Header">
<xsl:if test="$CurPos = 1">
<![CDATA[<ul class="list_Links">]]>
</xsl:if>
</xsl:variable>
<xsl:variable name="Footer">
<xsl:if test="$Last = $CurPos">
<![CDATA[</ul>]]>
</xsl:if>
</xsl:variable>
<xsl:value-of select="$Header" disable-output-escaping="yes" />
<li>
<a>
<xsl:attribute name="href">
<xsl:value-of select="substring-before($DisplayTitle,', ')"></xsl:value-of>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:value-of select="#Description"/>
</xsl:attribute>
<!-- <xsl:sort select="#Title0"/> -->
<xsl:value-of select="#Title0">
</xsl:value-of>
</a>
</li>
<xsl:value-of select="$Footer" disable-output-escaping="yes" />
</xsl:template>
I need to sort the title #Title0 field
as commented out below because it
causes an error.
Does anyone know whats causing this
error?
Yes, <xsl:sort/> can only be a child node of either <xsl:apply-templates> or <xsl:for-each> (and of <xsl:perform-sort> in XSLT 2.0).
Recommendation: Take at least a mini-course in XSLT and XPath so that you at least grok the fundamental concepts.

How to format a string to Pascal case in XSLT?

I'm trying to format strings in XSLT that needs to be in pascal case to be used appropriately for the application I'm working with.
For example:
this_text would become ThisText
this_long_text would become ThisLongText
Is it possible to also set this up where I can send an input to the format so I do not have to recreate the format multiple times?
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vLower" select=
"'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="vUpper" select=
"'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:call-template name="Pascalize">
<xsl:with-param name="pText" select="concat(., '_')"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="Pascalize">
<xsl:param name="pText"/>
<xsl:if test="$pText">
<xsl:value-of select=
"translate(substring($pText,1,1), $vLower, $vUpper)"/>
<xsl:value-of select="substring-before(substring($pText,2), '_')"/>
<xsl:call-template name="Pascalize">
<xsl:with-param name="pText"
select="substring-after(substring($pText,2), '_')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on this XML document:
<t>
<a>this_text</a>
<b>this_long_text</b>
</t>
produces the desired result:
<t>
<a>ThisText</a>
<b>ThisLongText</b>
</t>
BTW, this is camelCase and this is PascalCase
Here, two years after the fact, is an XSLT 2.0 solution:
<xsl:function name="fn:pascal-case">
<xsl:param name="string"/>
<xsl:value-of select="string-join(for $s in tokenize($string,'\W+') return concat(upper-case(substring($s,1,1)),substring($s,2)),'')"/>
</xsl:function>
It will pascalize either 'this_long_text' or 'this-long-text' to 'ThisLongText' because it breaks on any non-word characters.
In the regex flavors I am most familiar with (perl, pcre, etc.), an underscore is considered part of the '\w' character class (therefore not part of \W), but for XSLT 2.0 the XSD datatypes are used (http://www.w3.org/TR/xmlschema-2/) and '\w' is defined as:
[#x0000-#x10FFFF]-[\p{P}\p{Z}\p{C}] (all characters except the set of "punctuation", "separator" and "other" characters)
so '\W' includes an underscore.
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. ;-)
I was trying to achieve the "pascalizing" with the following XLST function call:
<xsl:value-of select="fn:replace(#name,'_(\w{1})','\U$1')"/>
Unfortunately the processor throws the error message "Invalid replacement string in replace():
\ character must be followed by \ or $"
the problem is the \U modifier which is supposed to do the uppercase conversion of the matched pattern. If I change it to
<xsl:value-of select="fn:replace(#name,'_(\w{1})','\\U$1')"/>
the output string contains the sequence '\U' because it is now esacped - but I don't want to escape it, I want it do be effective ;-) . I did test
<xsl:value-of select="fn:replace(#name,'_(\w{1})','$1')"/>
(without converting the match to uppercase) and that works fine. But of course it does no uppercasing, just removes underscores and replaces the letter after the underscore by itself instead of capitalizing it. Am I doing something wrong here or is the \U modifier simply not supported in the regex implementation of my XSLT processor?
Thanks to Dimitre, I was able to get most of the way there. When running my strings through the Pascalize template, the bit after the last '_' was cut off. There's probably a cleaner way of doing it, but here's the code I used:
<xsl:template name="Pascalize">
<xsl:param name="pText"/>
<xsl:if test="$pText">
<xsl:value-of select="translate(substring($pText,1,1), $vLower, $vUpper)"/>
<xsl:value-of select="substring-before(substring($pText,2), '_')"/>
<xsl:call-template name="Pascalize">
<xsl:with-param name="pText" select="substring-after(substring($pText,2), '_')"/>
</xsl:call-template>
<xsl:call-template name="GrabLastPart">
<xsl:with-param name="pText" select="$pText"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="GrabLastPart">
<xsl:param name="pText"/>
<xsl:choose>
<xsl:when test="contains($pText, '_')">
<xsl:call-template name="GrabLastPart">
<xsl:with-param name="pText" expr="substring-after($pText, '_')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($pText, 2)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

Resources