Living a SharePoint life

Wednesday, July 9, 2014

Configuring the Content Query Webpart to use seperate xslt template files

The Content Query Web Part is without doubt one of the most powerful webparts that come along with SharePoint. And because there are so many bits you can tweak, it’s probably one of the most complex as well.

As you might know I’ve used the CQWP in the past to create a calendar view for Milestones and Events. For these changes I’ve added the new templates directly into the existing ItemStyle.xsl file. Even thou this is a valid way to do it, I was a bit unhappy with the solution, because you always need to manipulate a SharePoint original file. If you make a mistake, you might brick all of your other CQWP used in the SiteCollection. So there has to be a better way to do this.
This post is



Luckily you can change the file containing the XSLT templates which are used to render the web part. This way you can store all of your own changes in separate files and if you misconfigure something you do not take down down the rest of your site.

To organize your templates I recommend you use a new file for every template you make. Alternatively you could use only one file and put all of your templates in one spot. This how every puts you back into the situation, that if you have an error in the xslt, all of the templates will fail to render. Also a best practice is you should name your files something like “YourNameItemStyle.xsl”. Appending ItemStyle.xsl to you own name you can recognize the purpose of the file.

Getting things started


I assume you already have a template to use. For this case I will use the Milestone template I have created and written about in one of my earlier posts.

Before we can begin, we need to create a new xsl file which holds our new template. Go ahead and create that new file and copy the entire content from the ItemStyle.xsl to your file. From here there are different approaches how to change the template file. Some blogs recommend deleting all templates from the file. Myself, I prefer to let the default and the HiddenSlots templates untouched and delete everything else. The first template after the default begins at row 81 and the last template ends at row 630. Your template file should looks something like this:

<xsl:stylesheet 
  version="1.0" 
  exclude-result-prefixes="x d xsl msxsl cmswrt"
  xmlns:x="http://www.w3.org/2001/XMLSchema" 
  xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" 
  xmlns:cmswrt="http://schemas.microsoft.com/WebParts/v3/Publishing/runtime"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
 <xsl:param name="ItemsHaveStreams">
  <xsl:value-of select="'False'" />
 </xsl:param>
 <xsl:variable name="OnClickTargetAttribute" select="string('javascript:this.target=&quot;_blank&quot;')" />
 <xsl:variable name="ImageWidth" />
 <xsl:variable name="ImageHeight" />
 <xsl:template name="Default" match="*" mode="itemstyle">
  <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="SafeImageUrl">
   <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
    <xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
   </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>
  <div class="item">
   <xsl:if test="string-length($SafeImageUrl) != 0">
    <div class="image-area-left"> 
     <a href="{$SafeLinkUrl}">
      <xsl:if test="$ItemsHaveStreams = 'True'">
       <xsl:attribute name="onclick">
        <xsl:value-of select="@OnClickForWebRendering"/>
       </xsl:attribute>
      </xsl:if>
      <xsl:if test="$ItemsHaveStreams != 'True' and @OpenInNewWindow = 'True'">
       <xsl:attribute name="onclick">
        <xsl:value-of disable-output-escaping="yes" select="$OnClickTargetAttribute"/>
       </xsl:attribute>
      </xsl:if>
      <img class="image" src="{$SafeImageUrl}" title="{@ImageUrlAltText}">
       <xsl:if test="$ImageWidth != ''">
        <xsl:attribute name="width">
         <xsl:value-of select="$ImageWidth" />
        </xsl:attribute>
       </xsl:if>
       <xsl:if test="$ImageHeight != ''">
        <xsl:attribute name="height">
         <xsl:value-of select="$ImageHeight" />
        </xsl:attribute>
       </xsl:if>
      </img>
     </a>
    </div>
   </xsl:if>
   <div class="link-item">
    <xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
    <a href="{$SafeLinkUrl}" title="{@LinkToolTip}">
     <xsl:if test="$ItemsHaveStreams = 'True'">
      <xsl:attribute name="onclick">
       <xsl:value-of select="@OnClickForWebRendering"/>
      </xsl:attribute>
     </xsl:if>
     <xsl:if test="$ItemsHaveStreams != 'True' and @OpenInNewWindow = 'True'">
      <xsl:attribute name="onclick">
       <xsl:value-of disable-output-escaping="yes" select="$OnClickTargetAttribute"/>
      </xsl:attribute>
     </xsl:if>
     <xsl:value-of select="$DisplayTitle"/>
    </a>
    <div class="description">
     <xsl:value-of select="@Description" />
    </div>
   </div>
  </div>
 </xsl:template>

 <!-- Enter you template here -->

 <xsl:template name="HiddenSlots" match="Row[@Style='HiddenSlots']" mode="itemstyle">
  <div class="SipAddress">
   <xsl:value-of select="@SipAddress" />
  </div>
  <div class="LinkToolTip">
   <xsl:value-of select="@LinkToolTip" />
  </div>
  <div class="OpenInNewWindow">
   <xsl:value-of select="@OpenInNewWindow" />
  </div>
  <div class="OnClickForWebRendering">
   <xsl:value-of select="@OnClickForWebRendering" />
  </div>
 </xsl:template>
</xsl:stylesheet>


Of course you can simply copy & paste the source from above.

Adding the basics


When working with the CQWP you sometimes need to get all raw values returned from webpart. To be able to show these values I also add the following template to my xsl file.

<xsl:template name="ShowAllRows" match="Row[@Style='ShowAllRows']" mode="itemstyle">
 <xsl:for-each select="@*">
  <xsl:value-of select="name()" /> : <xsl:value-of select="."/>
  <br/>
 </xsl:for-each>
 <br />
</xsl:template>


Because I often use functions from the ddwrt namespace, I add the following line to the <xsl:stylsheet> properties:

xmlns:ddwrt=http://schemas.microsoft.com/WebParts/v2/DataView/runtime


Save this file for the future. Finally add your own template code and don’t save it over the new file you just created, but instead save it as a new file and upload it into the Style Sheets location of your SiteCollection.

Tying things up


Next, we need a new CQWP on our site. Add the web part by editing your page and selecting Insert from the menu. Select Webpart and then add the CQWP from the list of available web parts. If you cannot find the CQWP, you might not have turned on the publishing feature yet.

When added the CQWP to your site, you can configure the basic settings like the targeting list or filtering the content. Afterwards you export the webpart and open the saved xml file in your favorite xml editor. I prefer Notepad++ a lot.

Tweaking from inside


As you might know the Content Query Webpart uses 3 different XSLT files to render the content on screen. These are:


  • ItemStyle.xsl
  • ContentQueryMain.xsl
  • Header.xsl

These 3 files are the default unless you configure otherwise in your exported xml file. To do so you must find the properly configuration inside of the xml file.

  • <property name="ItemXslLink" type="string"></property>
  • <property name="MainXslLink" type="string"></property>
  • <property name="HeaderXslLink" type="string"></property>

If you have a complex template you probably have to change more than one of these, but in most cases you will do fine by just using the ItemXslLink property. Configure the path were you will store our xsl file later. Your own xsl files however must be stored in the Style Library/XSL Style Sheets path, because all other locations will be considered as unsafe and do not work.

If you change on of these properties on a SiteCollection which is located beneath a managed path, you must use the complete relative path (e.g. /managed path/site name/Style Library/XSL Style Sheets/YouFileItemStyle.xsl)

Your setting should look something like this:

<property name="ItemXslLink" type="string">/managed path/site name/Style Library/XSL Style Sheets/YouFileItemStyle.xsl </property>


Save the exported CQWP file and upload it to your site. Open the webpart settings and select your template from the drop-down menu. You should now be able to see your own template at full glance.

Not there yet


I linked the CQWP to a task list, but not all information was offered to me. For instance I didn’t see the DueDate. This was kind of odd because I knew the template worked in the past.

By default, fields such as Title, Descriptions, and URL are provided. The challenge is to display more information than what the default fields provide. Lucky for us we can do so with the CQWP as well. So let’s open the CQWP configuration file again.

Search and locate the CommonViewFields property. By default, it will be blank. Adding additional fields to this property will make them available for display. We will need to add DueDate as a new field to the CommonViewFields property. The format of this property is [Internal Field Name],[Data Type Name]. The name is the internal field name and not necessarily the name you gave to the list.

To determine the internal field name, go to the List or Content Type settings and click on the new field. The internal field name will be part of the query string argument in the URL.

Here is everything I have added to my configuration:

<property name="CommonViewFields" type="string">StartDate,DateTime;DueDate,DateTime;AssignedTo,User;Status,Text;DocumentIconImageUrl,URL;OnClickForWebRendering,Text;</property>


If you add your own fields to this property, make sure you also add the two fields > DocumentIconImageUrl,URL;OnClickForWebRendering,Text; < as well, as it seems SharePoint has trouble if these are missing.

The DueDate field type is DateTime. For a complete list of field types, see this MSDN article:
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spfieldtype.aspx
http://social.technet.microsoft.com/Forums/ar/sharepoint2010programming/thread/8fc8e9df-4e89-42c9-a858-e15c59ca616e

Still not there


Ok, now that I have added the missing fields, I start to get errors when I try to edit the properties of the webpart.

As is turns out I had to add the fields I added to the CommonViewFields, to the DataMappings property as well. You do not need to include anything to the right of the colon. Be sure to include the trailing "|" symbol at the end of the property values.

Read about this here:
http://blog.pointycandy.com/2012/03/error-when-editing-cqwp-content-query.html

No comments:

Post a Comment

Featured Post

The Retro Powershell - Looking good in 8-Bit | Part 1

I wrote a little script that, when placed in your PowerShell Profile, will print a message similar to the old boot message you got from you...