To remove duplicates in CQWP using Xslt based approach the grouping capabilities could be used.
Input data
Suppose we have a list with the following customers
Customer A
Customer A
Customer B
Customer C
Customer C
Customer C
Customer D
Let's see how CQWP could be configured to display results without duplicates
Enable grouping
First step to enable grouping by customer name (title column) as shown on picture below
The CQWP results should look like this
Customize the results
Now our goal to transform results in such a way that only marked items will be displayed
Save a copy of ContentQueryMain.xsl
and modify it as described below
First, create the template for rendering grouped item
<xsl:template name="OuterTemplate.CallGroupItem">
<xsl:param name="CurPosition" />
<xsl:value-of disable-output-escaping="yes" select="$BeginListItem" />
<xsl:apply-templates select="." mode="itemstyle">
<xsl:with-param name="CurPos" select="$CurPosition" />
</xsl:apply-templates>
<xsl:value-of disable-output-escaping="yes" select="$BeginList" />
</xsl:template>
and then modify OuterTemplate.Body
to render grouped item
<xsl:template name="OuterTemplate.Body">
<xsl:param name="Rows" />
<xsl:param name="FirstRow" />
<xsl:param name="LastRow" />
<xsl:variable name="BeginColumn1" select="string('<ul class="dfwp-column dfwp-list" style="width:')" />
<xsl:variable name="BeginColumn2" select="string('%" >')" />
<xsl:variable name="BeginColumn" select="concat($BeginColumn1, $cbq_columnwidth, $BeginColumn2)" />
<xsl:variable name="EndColumn" select="string('</ul>')" />
<xsl:for-each select="$Rows">
<xsl:variable name="CurPosition" select="position()" />
<xsl:if test="($CurPosition >= $FirstRow and $CurPosition <= $LastRow)">
<xsl:variable name="StartNewGroup" select="@__begingroup = 'True'" />
<xsl:variable name="StartNewColumn" select="@__begincolumn = 'True'" />
<xsl:choose>
<xsl:when test="$cbq_isgrouping != 'True'">
<xsl:if test="$CurPosition = $FirstRow">
<xsl:value-of disable-output-escaping="yes" select="$BeginColumn" />
</xsl:if>
</xsl:when>
<xsl:when test="$StartNewGroup and $StartNewColumn">
<xsl:choose>
<xsl:when test="$CurPosition = $FirstRow">
<xsl:value-of disable-output-escaping="yes" select="$BeginColumn" />
<!--xsl:call-template name="OuterTemplate.CallHeaderTemplate"/-->
<xsl:call-template name="OuterTemplate.CallGroupItem">
<xsl:with-param name="CurPosition" select="$CurPosition" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="OuterTemplate.CallFooterTemplate"/>
<xsl:value-of disable-output-escaping="yes" select="concat($EndColumn, $BeginColumn)" />
<!--xsl:call-template name="OuterTemplate.CallHeaderTemplate"/-->
<xsl:call-template name="OuterTemplate.CallGroupItem">
<xsl:with-param name="CurPosition" select="$CurPosition" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$StartNewGroup">
<xsl:call-template name="OuterTemplate.CallFooterTemplate"/>
<!--xsl:call-template name="OuterTemplate.CallHeaderTemplate"/-->
<xsl:call-template name="OuterTemplate.CallGroupItem">
<xsl:with-param name="CurPosition" select="$CurPosition" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$StartNewColumn">
<xsl:choose>
<xsl:when test="$CurPosition = $FirstRow">
<xsl:value-of disable-output-escaping="yes" select="$BeginColumn" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of disable-output-escaping="yes" select="concat($EndColumn, $BeginColumn)" />
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
<!--xsl:call-template name="OuterTemplate.CallItemTemplate">
<xsl:with-param name="CurPosition" select="$CurPosition" />
</xsl:call-template-->
<xsl:if test="$CurPosition = $LastRow">
<xsl:if test="$cbq_isgrouping = 'True'">
<xsl:call-template name="OuterTemplate.CallFooterTemplate"/>
</xsl:if>
<xsl:value-of disable-output-escaping="yes" select="$EndColumn" />
</xsl:if>
</xsl:if>
</xsl:for-each>
</xsl:template>
You could find the source code here
The last step is to replace Main Xsl with custom one (for example,
export web part and specify Main Xsl property)
For more information about customizing CQWP please follow this article.
Result