Reputation: 83
I'm trying to use Muenchian grouping to display company policy documents in a hierarchical way. The policy documents are all added to SharePoint and tagged with a Language, a category and a document type. I'm then using the XML that this creates.
I need to take the data from 2 merged lists. The way SharePoint works, my XML looks like this (with a Rows element for each SharePoint list): I've had to simplify this to remove the hundreds of attributes that SP adds as it went over the stackoverflowsize limit, but the structure is accurate.
<dsQueryResponse>
<Rows>
<Row Title="Testitem" Category="Category 1" Language="English" DocumentType="Content" />
</Rows>
<Rows>
<Row Title="Doc1" Category="Category 1" Language="English" DocumentType="Policy" />
<Row Title="Policy2" Category="Category 2" Language="English" DocumentType="Policy" />
<Row Title="Policy3" Category="Category 1" Language="Nederlands (Dutch)" DocumentType="Form" />
</Rows>
</dsQueryResponse>
Current xsl looks like this:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:SharePoint="Microsoft.SharePoint.WebControls"
xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"
xmlns:agg="http://schemas.microsoft.com/sharepoint/aggregatesource"
xmlns:asp="http://schemas.microsoft.com/ASPNET/20"
xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
xmlns:ddwrt2="urn:frontpage:internal"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xsl msxsl ddwrt"
ddwrt:oob="true"
>
<xsl:output indent="yes" omit-xml-declaration="yes" />
<xsl:key name="byLANGUAGE" match="/dsQueryResponse/Rows/Row" use="@Language" />
<xsl:key name="byCATEGORY" match="/dsQueryResponse/Rows/Row" use="concat(@Language, '+', @Category)" />
<xsl:template match="/">
<xsl:apply-templates select="/dsQueryResponse/Rows/Row[count(. | key('byLANGUAGE', @Language)[1]) = 1]/@Language">
<xsl:sort select="." order="ascending" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="@Language">
<br /><b>Below you can see all policies in <xsl:value-of select="." /></b><br /><br />
<xsl:variable name="thisLanguage" select="key('byLANGUAGE', .)" />
<xsl:apply-templates select="$thisLanguage[count(. | key('byCATEGORY', concat(@Language, '+', @Category))[1])= 1]/@Category">
<xsl:sort select="." order="ascending" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="@Category">
<br />Category: <xsl:value-of select="." />
<xsl:apply-templates select="key('byCATEGORY', concat(../@Language, '+', .))" />
</xsl:template>
<xsl:template match="/dsQueryResponse/Rows/Row">
<br />Title: <xsl:value-of select="@Title" />
</xsl:template>
</xsl:stylesheet>
and current result looks like this (a mess):
Below you can see all policies in English Category: Category 1 Title: Testitem Category: Category 2 Title: Policy2 Below you can see all policies in English Category: Category 1 Title: Testitem Category: Category 2 Title: Policy2 Below you can see all policies in Nederlands (Dutch) Category: Category 1 Title: Policy3 **My desired output is:** Below you can see all policies in English Category: Category 1 Title: Testitem Title: Doc1 Category: Category 2 Title: Policy2 Below you can see all policies in Nederlands (Dutch) Category: Category 1 Title: Policy3
So I seem to be getting lots of duplication, presumably because something is getting called twice, once for each of the Rows elements? I'm a novice with XSL so any help would be appreciated.
========== UPDATE ==========
The code below now works for me in SharePoint (the bulky looking Choose statements aren't technically necessary but I needed them to get rid of the non-English characters for the JQuery that I've put on top of this):
Full XSLT:
<xsl:stylesheet xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" xmlns:agg="http://schemas.microsoft.com/sharepoint/aggregatesource" 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" ddwrt:oob="true">
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="byLANGUAGE" match="/dsQueryResponse/Rows/Row" use="@Language" />
<xsl:key name="byCATEGORY" match="/dsQueryResponse/Rows/Row" use="concat(@Language, '+', @Category)" />
<xsl:template match="/">
<div id="tabs" style="display:none;">
<!--Create tabs-->
<ul>
<xsl:apply-templates select="/dsQueryResponse/Rows/Row[count(. | key('byLANGUAGE', @Language)[2]) = 1]/@Language">
<xsl:sort select="." order="ascending" />
</xsl:apply-templates>
</ul>
<!--Create content-->
<xsl:apply-templates select="/dsQueryResponse/Rows/Row[count(. | key('byLANGUAGE', @Language)[2]) = 1]/@Language" mode="pass2">
<xsl:sort select="." order="ascending" />
</xsl:apply-templates>
</div>
</xsl:template>
<!--Do a first pass to create the tabs -->
<xsl:template match="@Language">
<li>
<xsl:choose>
<xsl:when test=". = 'English'"><xsl:text disable-output-escaping="yes"><a href="#English"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
<xsl:when test=". = 'Bahasa'"><xsl:text disable-output-escaping="yes"><a href="#Bahasa"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
<xsl:when test=". = '简体中文 (Chinese)'"><xsl:text disable-output-escaping="yes"><a href="#Chinese"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
<xsl:when test=". = 'Nederlands (Dutch)'"><xsl:text disable-output-escaping="yes"><a href="#Dutch"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
<xsl:when test=". = 'Français (French)'"><xsl:text disable-output-escaping="yes"><a href="#French"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
<xsl:when test=". = 'Deutsch (German)'"><xsl:text disable-output-escaping="yes"><a href="#German"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
<xsl:when test=". = 'Italiano (Italian)'"><xsl:text disable-output-escaping="yes"><a href="#Italian"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
<xsl:when test=". = '日本語 (Japanese)'"><xsl:text disable-output-escaping="yes"><a href="#Japanese"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
<xsl:when test=". = '한국의 (Korean)'"><xsl:text disable-output-escaping="yes"><a href="#Korean"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
<xsl:when test=". = 'Polski (Polish)'"><xsl:text disable-output-escaping="yes"><a href="#Polish"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
<xsl:when test=". = 'Português (Portuguese)'"><xsl:text disable-output-escaping="yes"><a href="#Portuguese"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
<xsl:when test=". = 'PyccĸИЙ (Russian)'"><xsl:text disable-output-escaping="yes"><a href="#Russian"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
<xsl:when test=". = 'Castellano (Spanish)'"><xsl:text disable-output-escaping="yes"><a href="#Spanish"></xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes"></a></xsl:text></xsl:when>
</xsl:choose>
</li>
</xsl:template>
<!--and a second pass to do everything else-->
<xsl:template match="@Language" mode="pass2">
<xsl:choose>
<xsl:when test=". = 'English'"><xsl:text disable-output-escaping="yes"><div id="English"></xsl:text></xsl:when>
<xsl:when test=". = 'Bahasa'"><xsl:text disable-output-escaping="yes"><div id="Bahasa"></xsl:text></xsl:when>
<xsl:when test=". = '简体中文 (Chinese)'"><xsl:text disable-output-escaping="yes"><div id="Chinese"></xsl:text></xsl:when>
<xsl:when test=". = 'Nederlands (Dutch)'"><xsl:text disable-output-escaping="yes"><div id="Dutch"></xsl:text></xsl:when>
<xsl:when test=". = 'Français (French)'"><xsl:text disable-output-escaping="yes"><div id="French"></xsl:text></xsl:when>
<xsl:when test=". = 'Deutsch (German)'"><xsl:text disable-output-escaping="yes"><div id="German"></xsl:text></xsl:when>
<xsl:when test=". = 'Italiano (Italian)'"><xsl:text disable-output-escaping="yes"><div id="Italian"></xsl:text></xsl:when>
<xsl:when test=". = '日本語 (Japanese)'"><xsl:text disable-output-escaping="yes"><div id="Japanese"></xsl:text></xsl:when>
<xsl:when test=". = '한국의 (Korean)'"><xsl:text disable-output-escaping="yes"><div id="Korean"></xsl:text></xsl:when>
<xsl:when test=". = 'Polski (Polish)'"><xsl:text disable-output-escaping="yes"><div id="Polish"></xsl:text></xsl:when>
<xsl:when test=". = 'Português (Portuguese)'"><xsl:text disable-output-escaping="yes"><div id="Portuguese"></xsl:text></xsl:when>
<xsl:when test=". = 'PyccĸИЙ (Russian)'"><xsl:text disable-output-escaping="yes"><div id="Russian"></xsl:text></xsl:when>
<xsl:when test=". = 'Castellano (Spanish)'"><xsl:text disable-output-escaping="yes"><div id="Spanish"></xsl:text></xsl:when>
</xsl:choose>
<b>Below you can see all policies in <xsl:value-of select="." /></b><br /><br/>
<div class="accordion">
<xsl:variable name="thisLanguage" select="key('byLANGUAGE', .)" />
<xsl:apply-templates select="$thisLanguage[count(. | key('byCATEGORY', concat(@Language, '+', @Category))[2])= 1]/@Category">
<xsl:sort select="." order="ascending" />
</xsl:apply-templates>
</div>
<xsl:text disable-output-escaping="yes"></div></xsl:text>
</xsl:template>
<xsl:template match="@Category">
<h3>
<xsl:value-of select="." />
</h3>
<div class="accordionContent">
<xsl:apply-templates select="key('byCATEGORY', concat(../@Language, '+', .))"/>
</div>
</xsl:template>
<xsl:template match="/dsQueryResponse/Rows/Row">
<div class="policy-item">
<div class="policy-item-title">
<xsl:value-of select="@Title" />
</div>
<xsl:if test="@ItemHtml != ''">
<div class="policy-item-content">
<xsl:value-of select="@ItemHtml" disable-output-escaping="yes" />
</div>
</xsl:if>
</div>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2
Views: 177
Reputation: 338208
Here is what I would do:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:SharePoint="Microsoft.SharePoint.WebControls"
xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"
xmlns:agg="http://schemas.microsoft.com/sharepoint/aggregatesource"
xmlns:asp="http://schemas.microsoft.com/ASPNET/20"
xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
xmlns:ddwrt2="urn:frontpage:internal"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="msxsl ddwrt SharePoint __designer agg asp d ddwrt2 x"
ddwrt:oob="true"
>
<xsl:output method="html" indent="yes" omit-xml-declaration="yes" />
<xsl:key name="kRowByLanguage" match="Row" use="@Language" />
<xsl:key name="kRowByCategory" match="Row" use="concat(@Language, '+', @Category)" />
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="dsQueryResponse/Rows" />
</body>
</html>
</xsl:template>
<xsl:template match="Rows">
<xsl:apply-templates mode="language" select="Row[
count(. | key('kRowByLanguage', @Language)[1]) = 1
]">
<xsl:sort select="@Language" order="ascending" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="Row" mode="language">
<xsl:variable name="myCategory" select="concat(@Language, '+', @Category)" />
<div class="language">
<div>
<xsl:text>Below you can see all policies in </xsl:text>
<xsl:value-of select="@Language" />
</div>
<div>
<xsl:apply-templates mode="category" select="key('kRowByLanguage', @Language)[
count(. | key('kRowByCategory', $myCategory)[1]) = 1
]">
<xsl:sort select="@Category" order="ascending" />
</xsl:apply-templates>
</div>
</div>
</xsl:template>
<xsl:template match="Row" mode="category">
<xsl:variable name="myCategory" select="concat(@Language, '+', @Category)" />
<div class="catecory">
<div>
<xsl:text>Category: </xsl:text>
<xsl:value-of select="@Category" />
</div>
<div>
<xsl:apply-templates mode="title" select="key('kRowByCategory', $myCategory)" />
</div>
</div>
</xsl:template>
<xsl:template match="Row" mode="title">
<div>
<xsl:text>Title: </xsl:text>
<xsl:value-of select="@Title" />
</div>
</xsl:template>
</xsl:stylesheet>
output (I generally recommend using CSS for formatting your output, instead of using <br>
):
<html>
<body>
<div class="language">
<div>Below you can see all policies in English</div>
<div>
<div class="catecory">
<div>Category: Category 1</div>
<div>
<div>Title: Testitem</div>
<div>Title: Doc1</div>
</div>
</div>
</div>
</div>
<div class="language">
<div>Below you can see all policies in Nederlands (Dutch)</div>
<div>
<div class="catecory">
<div>Category: Category 1</div>
<div>
<div>Title: Policy3</div>
</div>
</div>
</div>
</div>
</body>
</html>
The primary change is the move of the subgroup key (language + category) into the variable $myCategory
, this enables selecting the right nodes in your double grouping.
Your original expression:
$thisLanguage[count(. | key('byCATEGORY', concat(@Language, '+', @Category))[1])= 1]
refers to the wrong context inside the predicate (it refers to $thisLanguage
, which does not have @Language or @Category). Moving the concat(...)
out of this expression generates the correct results.
The secondary change is adding some structure to the output so it can be targeted more easily via CSS.
Also note the output method and the use of different template modes.
General hint: You have many namespace declarations in your stylesheet. Remove any you don't actively use in the stylesheet.
Upvotes: 1