In your Office Sharepoint Server 2007 site you can display a dynamic view of content on a page by using the Content Query Web Part. This post from Tyler Butler and this one from Heather Solomon helped me on my way.

With the help of these blogs it is not very hard to create a single column presentation of your content. Every single item gets processed by the ItemStyle.xsl found in the Style library / XSL Style sheets section. But if you would like to order your content dynamically in 2 columns you will need to build some extra coding in the ItemStyle.xsl and in the ContentQueryMain.xsl, which is also found in the XSL Style sheets section.

The default templates present our data in a single column:
Single column Content Query Webpart

But for some sites we might want to show our data inside 2 columns:
2 Column Content Query Webpart


I will not make use of the header.xsl file in this example because it makes it harder to read and in my opinion it is better to keep all rendering code of a style accessible in one spot for future editing.

If we want to be able to render 2 columns, the ItemStyle.xsl must know the item number which is currently being processed. To generate valid html we must also know when we are processing the last item, otherwise we might finish our table with an incorrect number of <td> tags. To provide our style in the ItemStyle.xsl with the 2 required parameters open up the ContentQueryMain.xsl file in your favorite text editor. Search for the tag “<xsl:call-template name=”OuterTemplate.CallItemTemplate”>” and modify it in the following way:

<xsl:call-template name=”OuterTemplate.CallItemTemplate”>
 <xsl:with-param name=”CurPosition” select=”$CurPosition” />
 <xsl:with-param name=”LastRow” select=”$LastRow” />
</xsl:call-template>

This will pass the CurPosition and LastRow parameter to the OuterTemplate.CallItemTemplate which we must alter to accept the LastRow parameter. Search for the “<xsl:template name=”OuterTemplate.CallItemTemplate”>” template section and make sure you have the CurPostion and LastRow parameters in the top section of the template:

<xsl:template name=”OuterTemplate.CallItemTemplate”>
 <xsl:param name=”CurPosition” />
 <xsl:param name=”LastRow” />
 <xsl:choose>
  <xsl:when test=”@Style=’Multicolumn_example'”>
   <xsl:apply-templates select=”.” mode=”itemstyle”>
    <xsl:with-param name=”CurPos” select=”$CurPosition” />
    <xsl:with-param name=”Last” select=”$LastRow” />
   </xsl:apply-templates>
  </xsl:when>

  <xsl:otherwise>
   <xsl:apply-templates select=”.” mode=”itemstyle”>
   </xsl:apply-templates>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

Inside the same template section add a <xsl:when> node for every template that should access the new parameters. Take a look at the <xsl:when test=”@Style=’Multicolumn_example'”> section to see how the parameters are provided.

Now we are finished with the changes in the ContentQueryMain.xsl file and it’s time to open up our ItemStyle.xsl file to add the Multicolumn_example style.

In the example below I created a tableStart variable which will only render when our CurPos equals 1. This variable will add a table tag. The tableEnd variable will render the closing tags when our CurPos equals the Last item number. Inside the tableRowItem variable we place the html content that is used for the single item. The content of this item is the same for the left and for our right column. The logic that renders the right and left column is put into the tableRow variable.

<xsl:template name=”Multicolumn_example” match=”Row[@Style=’Multicolumn_example’]” mode=”itemstyle”>
 <xsl:param name=”CurPos” />
 <xsl:param name=”Last” />
 <xsl:variable name=”tableStart“>
  <xsl:if test=”$CurPos = 1″>
   <![CDATA[<table width=”100%” border=”0″>]]>
  </xsl:if>
 </xsl:variable>
 <xsl:variable name=”tableEnd“>
  <xsl:if test=”$CurPos = $Last”>
   <![CDATA[</table>]]>
  </xsl:if>
 </xsl:variable>
 <xsl:variable name=”tableRowItem“>
  <![CDATA[<td>]]><xsl:value-of select=”@Title”/><![CDATA[</td>]]>
 </xsl:variable>
 <xsl:variable name=”tableRow“>
  <xsl:choose>
   <xsl:when test=”$CurPos mod 2 = 1″>
    <![CDATA[<tr>]]>
    <xsl:value-of select=”$tableRowItem” disable-output-escaping=”yes”/>
    <xsl:if test=”$CurPos = $Last”>
     <![CDATA[<td></td></tr>]]>
    </xsl:if>
   </xsl:when>
   <xsl:otherwise>
    <xsl:value-of select=”$tableRowItem” disable-output-escaping=”yes”/>
    <![CDATA[</tr>]]>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:variable>
 <xsl:value-of select=”$tableStart” disable-output-escaping=”yes”/>
 <xsl:value-of select=”$tableRow” disable-output-escaping=”yes”/>
 <xsl:value-of select=”$tableEnd” disable-output-escaping=”yes”/>
</xsl:template>

Inside the tableRow variable I made use of the mod calculation “$CurPos mod 2 = 1” to decide in which column the content should be processed. It returns false if the current position can be divided by 2 and true if it can’t. We add an extra “$CurPos = $Last” check in the left column to render an empty right column when it is the last item. On the bottom of our template we combine all logic by calling the defined variables.

That’s it! Now select the “Multicolumn_example” style in your content query tool webpart and you should see your content divided over 2 columns. Click here to download the modified xsl files in this example.

[update 15-11-2007]
Thomek submitted a very simple method to create a multi-column result which works fine in simple situations. I tried it at our customer, but the results where not 100% correctly. I suggest that you can always try first, if this method works in your situation, as it’s a fast solution and doesn’t require editting in the xsl files:

  • Go to the Presentation properties of the CQWP and set Grouping and Sorting to Title
  • Set the number of columns to 2 or more
  • Go to the Styles properties of the CQWP and set the Group style to Whitespace