I ran into this before and came up with a solution that is not as clean as one would have hoped, but it worked for me, granted that it's a dirty trick/workaround and it's far from being perfect.
I tested it in SharePoint 2010, but from what I can see from your description, nothing has changed in SharePoint 2013 (read: dealing with multiselection box in InfoPath and SharePoint is a real pita).
Ingredients:
- a QueryString parameter declared on the XsltListViewWebPart
- a filter on the XsltListViewWebPart
- a CEWP webpart on the view page
- an external file (stored for example in SiteAssets) with a bit of javascript and linked to the CEWP webpart
- jquery
- underscore.js
Description:
Open the page containing the XsltLVWP in SharePoint Designer and add a QueryString parameter, call it eg. Category.
Then, create a filter with this criterion: Category Contains [Category]
where [Category] is the parameter you've just declared.
Add a file to the SiteAssets library, call it eg. getCategories.js.
The content should look more or less like this:
<script type="text/javascript">
function retrieveListItems() {
var clientContext = new SP.ClientContext();
var list = clientContext.get_web().get_lists().getByTitle('YourList');
var camlQuery = new SP.CamlQuery();
// retrieve only the category field
camlQuery.set_viewXml('<View><ViewFields><FieldRef Name="Category"/></ViewFields></View>');
this.listItems = list.getItems(camlQuery);
clientContext.load(listItems);
clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}
function onQuerySucceeded(sender, args) {
var listItemEnumerator = listItems.getEnumerator();
var allCategories = [];
var i;
while (listItemEnumerator.moveNext()) {
var listItem = listItemEnumerator.get_current();
var category = listItem.get_item('Category');
//we need to split the comma separated string
if (category.indexOf(',') !== -1){
var tempCategories = category.split(',');
for (i = 0; i < tempCategories.length; i++){
allCategories[allCategories.length] = tempCategories[i].trim(); //remove initial white space
}
}
else{
allCategories[allCategories.length] = category;
}
}
// we need unique categories
allCategories = _.uniq(allCategories); //underscore.js uniq method
// add all unique categories to the dropdown
for (i = 0; i < allCategories.length; i++){
var option = $('<option>');
option.val(allCategories[i]);
option.text(allCategories[i]);
$('#categoriesDdl').append(option);
}
$('#categoriesDdl').on('change', function(){
window.location.href = "/yuorsite/list/page.aspx?" + "Category=" + $('#categoriesDdl').val();
});
}
function onQueryFailed(sender, args) {
//....
}
ExecuteOrDelayUntilScriptLoaded(retrieveListItems, 'sp.js')
</script>
<!-- this is our custom filter -->
<select id="categoriesDdl">
<option>---select a category</option>
</select>
The code creates a dropdown list with all the unique categories extracted from the category field and append the selected value to a querystring parameter, thus triggering the filter on the XsltLVWB.
Add a CEWP to your view page and link the getCategories.js file.
Known issues:
- having set a parameter and a filter, the first time the page is rendered, nothing is shown
- if your categories have overlapping names, then the contains filter will produce unwanted results (eg. category 1 and category 10 will both be shown when your filter is = 1)
Other solutions:
considering that you're on SharePoint 2013, I would go the REST way and build my own datagrid with full custom filters (for the category filter dropdown the logic would be more or less the same).
Here you can find some inspiration.