Problem:
Building a dynamic tree of a list based on a choice column (with multi-value select enabled, i.e. checkboxes) can't be done using views and Group By. Simply because Group By does not list columns with multi-value select in its options.
So, if you have a list with the following information:

You can build a view to group by Status (Choice as Dropdown or Radios), but not group by Competency (Choice as Checkboxes).
Solution (or workaround if you like)
In brief, the solution to this is to use a Data View Web Part (connected to the list), and use a custom XSL transformation which pivots according to the multi-value column, to get something like this:

The outline is as follows:
- Create a list with a column of type Choice (as checkboxes)
- Create a Data View Web Part in SharePoint Designer from this list
- Build the XSLT to enable pivoting on the choices available from 1.
- Use an dynamic script to enable a Tree View with expand/collapse capabilities.
- Save the new XSLT to the DVWP
Details:
Step 1: Create a list with a column of type Choice (as checkboxes)
Do I need to explain this?! Well I will share the list I have created so you can follow the columns design:
| Column | Type | Remarks |
| Title | Single line of text | Built-in |
| Status | Choice | Radio: In Progress, Proposed, Stalled |
| Competency | Choice | Checkbox: Software, Hardware, Services, Logistics |
| Created By | Person or Group | Built-in |
| Modified By | Person or Group | Built-in |
Step 2: Create a Data View Web Part (DVWP) in SharePoint Designer (SPD) from this list
You have two ways to create a DVWP from a list in SharePoint. You can drop a web part of the Stuff list above using the browser, and use SPD to convert that web part to a DVWP. This is simply accomplished by right-clicking and choosing "Convert to XSLT Data View".
Another way is to use SPD directly and drag the list (from the Data Sources) to a web part zone. Both should give you the same result.
Step 3: Build the XSLT to enable pivoting on the choices available from Step 1
The idea here is to change the default XSLT and use another transformation that:
- Keeps a list of choices as XML (that's a gotcha)
- Loops through the list of choices doing the following:
- Generating a header for each choice
- Looping through all the rows in the list, and filtering according to the value of Choice.
- Dumping those who match the header/choice as a list of items (or table rows, or spans, or ...)
Remember that the idea behind XSLT is take the XML representing the SharePoint list data, and transforming it into HTML. Whatever HTML tags you use is up to you. I used <ul> and <li> because I wanted to make use of a ready made dynamic script that can transform that into a Tree View.
See below the XSLT I used with the Stuff list.
Step 4: Use an dynamic script to enable a Tree View with expand/collapse capabilities
I actually have embedded that in the above XSLT. I have used the Simple Tree Menu from DynamicDrive.
You need to follow the instructions in the above site to include necessary files for like the CSS, Images, and Script files. Here is what I did:
- Include the below in the "PlaceHolderAdditionalPageHead" content control.
<script type="text/javascript" src="scripts/simpletreemenu.js">
/***********************************************
* Simple Tree Menu- © Dynamic Drive DHTML code library (www.dynamicdrive.com)
* This notice MUST stay intact for legal use
* Visit Dynamic Drive at http://www.dynamicdrive.com/ for full source code
***********************************************/
</script>
<link rel="stylesheet" type="text/css" href="styles/simpletree.css" />
- Import the files to images, scripts, and styles folders under the root of my site, using SPD
- Change the references to images and scripts to match where I put them. e.g. change the URL to "images/open.gif" in CSS, for instance.
Step 5: Save the new XSLT to the DVWP
Using SPD, right click on the web part in design mode and click Web Part Properties. Change the XSLT using the XSLT Editor.
And you're done. You should see the final result as shown above.
Resources:
XSLT:
The following is document and should be self-explanatory.
<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal">
<xsl:output method="html" indent="no"/>
<xsl:decimal-format NaN=""/>
<xsl:param name="dvt_apos">'</xsl:param>
<xsl:variable name="dvt_1_automode">0</xsl:variable>
<!--
The following variable lists all options available to pivot around.
the gotcha is that you need to update this, whenever yo change the schema of the list in SharePoint.
In other words, if you change the Choice column by adding/modifying/deleting value in SharePoint List Settings, then
you need to come back to this and synchronize it manually.
Let me know if you have a better approach.
-->
<xsl:variable name="Competencies">
<Competency Text="Software" />
<Competency Text="Hardware" />
<Competency Text="Services" />
<Competency Text="Logistics" />
</xsl:variable>
<xsl:template match="/" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:SharePoint="Microsoft.SharePoint.WebControls">
<xsl:call-template name="dvt_1"/>
</xsl:template>
<xsl:template name="dvt_1">
<xsl:variable name="dvt_StyleName">Table</xsl:variable>
<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row"/>
<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows"/>
</xsl:call-template>
</xsl:template>
<!-- the following is the main template which generates the skeleton of the pivot tree -->
<xsl:template name="dvt_1.body">
<xsl:param name="Rows"/>
<!--
An optinal HTML to have links to expan and collapse coming from Simple Tree Menu
More here: http://www.dynamicdrive.com/dynamicindex1/navigate1.htm
-->
<a href="javascript:ddtreemenu.flatten('treemenu1', 'expand')">Expand All</a> | <a href="javascript:ddtreemenu.flatten('treemenu1', 'contact')">Contact All</a>
<!-- the container of the tree, and need to be marked with treeview style for trigeting the tree view script -->
<ul id="treemenu1" class="treeview">
<!--
looping through the options from the above XML varaible
You need to use the msxsl:node-set funation to build a node set from the variable
See MSDN for more info
-->
<xsl:for-each select="msxsl:node-set($Competencies)/Competency">
<!-- keep track of the competeny text value (Software, Hardware, ...) before going to another scope -->
<xsl:variable name="Competency" select="@Text" />
<li>
<!-- dump the value of competency in an list item <li> -->
<xsl:value-of select="$Competency"/>
<ul>
<!--
loop through all rows and call the group template which will handling the filtering
passing competency as a variable
-->
<xsl:for-each select="$Rows">
<xsl:call-template name="Competency.Group">
<xsl:with-param name="CompetencyValue" >
<xsl:value-of select="$Competency"/>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</ul>
</li>
</xsl:for-each>
</ul>
<!-- a script coming from Simple Tree Menu above -->
<script type="text/javascript">
//ddtreemenu.createTree(treeid, enablepersist, opt_persist_in_days (default is 1))
ddtreemenu.createTree("treemenu1", true)
ddtreemenu.createTree("treemenu2", false)
</script>
</xsl:template>
<!-- this is a template that will do the real decision to include or not include a list item based on competency value -->
<xsl:template name="Competency.Group">
<xsl:param name="CompetencyValue"/>
<!-- only display competency when Comptency column contains the value -->
<xsl:if test="contains(@Competency, $CompetencyValue)">
<li>
<!-- dump the item data -->
<b><xsl:value-of select="@Title" /></b> : <xsl:value-of select="@Competency"/>
</li>
</xsl:if>
</xsl:template>
</xsl:stylesheet>