So I've been banging my head against the wall for a while and am looking for some help. I'm trying to create a new itemstyle in sharepoint designer that basically checks each item in a task list and then tallies up the total number of Completed, In Progress, and Not Started statuses. The problem is to my knowledge, xsl doesn't have mutable variables. What I have so far is this:
<xsl:variable name="sChk">
<xsl:value-of select="#Status"/>
</xsl:variable>
<xsl:for-each select="#Status">
<xsl:if test="$sChk = 'Completed' ">
<!-- Add to Completed Counter -->
</xsl:if>
<xsl:if test="$sChk = 'In Progress' ">
<!-- Add to In Progress Counter -->
</xsl:if>
<xsl:if test="$sChk = 'Not Started' ">
<!-- Add to Not Started Counter -->
</xsl:if>
<br/>
</xsl:for-each>
Out Of Loop:
Total Completed: <!-- Completed Value -->
Total In Progress: <!-- In Progress Value -->
Total Not Started: <!-- Not Started Value -->
Any and all help would be greatly appreciated, thanks!
EDIT: So I've also tried this recursive method as well but this isn't working either...
<xsl:param name="cCount" select="0"/>
<xsl:param name="ipCount" select="0"/>
<xsl:param name="nsCount" select="0"/>
<xsl:choose>
<xsl:when test="$sChk = 'Completed'">
<xsl:call-template name="PSRView2.0">
<xsl:with-param name="cCount" select="$cCount +1"/>
<xsl:with-param name="ipCount" select="$ipCount"/>
<xsl:with-param name="nsCount" select="$nsCount"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$sChk = 'In Progress'">
<xsl:call-template name="PSRView2.0">
<xsl:with-param name="cCount" select="$cCount"/>
<xsl:with-param name="ipCount" select="$ipCount +1"/>
<xsl:with-param name="nsCount" select="$nsCount"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$sChk = 'Not Started'">
<xsl:call-template name="PSRView2.0">
<xsl:with-param name="cCount" select="$cCount"/>
<xsl:with-param name="ipCount" select="$ipCount"/>
<xsl:with-param name="nsCount" select="$nsCount +1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$cCount"/>
<xsl:value-of select="$ipCount"/>
<xsl:value-of select="$nsCount"/>
</xsl:otherwise>
</xsl:choose>
You are correct in that in XSLT variables are immutable. What you need to use in your case those is the count function, which counts up all the items in a node-set. Something like this:
<xsl:variable name="completed" select="count(task[#Status='Completed'])" />
<xsl:variable name="inprogress" select="count(task[#Status='In Progress'])" />
<xsl:variable name="notstarted" select="count(task[#Status='Not Started'])" />
Total: <xsl:value-of select="$completed + $inprogress + $notstarted" />
Of course, you would need to replace 'task' with what ever element name you are using in your XSLT.
Without seeing your XML, it is hard to give a precise answer, but as an example, consider the following XML
<tasklist>
<task status="Completed" />
<task status="Completed" />
<task status="In Progress" />
</tasklist>
Then the XSLT (to get totals only), would look like this
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="tasklist">
<xsl:variable name="completed" select="count(task[#Status='Completed'])" />
<xsl:variable name="inprogress" select="count(task[#Status='In Progress'])" />
<xsl:variable name="notstarted" select="count(task[#Status='Not Started'])" />
Total: <xsl:value-of select="$completed + $inprogress + $notstarted" />
</xsl:template>
</xsl:stylesheet>
Notice how you need to be positioned on the parent element of all the individual 'task' elements here. As an alternative, you can do something like this...
<xsl:variable name="completed" select="count(//task[#Status='Completed'])" />
Which would count task elements wherever they are in the XML.
You could even do the following, if you really didn't know the element name, but were sure there were no other elements with a 'Status' attibute:
<xsl:variable name="completed" select="count(//*[#Status='Completed'])" />
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.
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?
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>
How can I create a link to the rest of the paragraph in an announcement in SharePoint, that displays the word: read more
Cheers
I've found that the cleanest, easiest way to do this is to create a template in ItemStyle.xsl which selects a substring of the body content of the announcement and displays a link below to the article itself.
After adding the following code to your ItemStyle.xsl file (in SharePoint Designer navigate to the 'Style Library/XSL Style Sheets' folder), you can modify the web part through the browser, and change the Item Style (Presentation/Styles) to 'ReadMoreAnnouncements'. This code keeps the amount of characters displayed to 190 characters (see the substring($bodyContent,1,190 function call).
<xsl:template name="removeMarkup">
<xsl:param name="string" />
<xsl:choose>
<xsl:when test="contains($string, '<')">
<xsl:variable name="nextString">
<xsl:call-template name="removeMarkup">
<xsl:with-param name="string" select="substring-after($string, '>')" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="concat(substring-before($string, '<'), $nextString)" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="ReadMoreAnnouncements" match="Row[#Style='ReadMoreAnnouncements']" mode="itemstyle">
<br />
<div class="RMAnnouncementsTitle">
<xsl:value-of select="#Title" />
</div>
<div class="RMAnnouncementsBody">
<xsl:variable name="bodyContent">
<xsl:call-template name="removeMarkup">
<xsl:with-param name="string" select="#Body"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="substring($bodyContent,1,190)" />
...
<br />
<a>
<xsl:attribute name="href">
/Lists/Announcements/DispForm.aspx?ID=
<xsl:value-of select="#ID">
</xsl:value-of>
</xsl:attribute>
<xsl:attribute name="class">
RMAnnouncementsMoreLink
</xsl:attribute>
read more
</a>
</div>
</xsl:template>
This should definitely work, and it's very very easy to implement.
If you have a page and can edit it in SharePoint Designer, try this.
If you want to have a web part that shows the announcement the way you want, try this.