I'm building a custom Xsl to customize the rendering of a ContentByQueryWebPart. This webpart is targeting pictures

In the results, I would like to generate a link to the corresponding dispform.aspx, in order to show the details of the target picture.

How can I generate such link ?

By now, I have created this piece of Xsl to generate the link in my custom ItemStyle.xsl :

<xsl:variable name="DispFormUrl">
        select="concat($SiteUrl, '/_layouts/listform.aspx?PageType=4&amp;ListId={',@ListId, '}&amp;ID=', @ID)" 

This is working when I work at the root of the site collection. However, this does not works if the results are from another web within the site collection.

How can I correct my xsl to support any location ?


I ended up by creating my Xslt extension functions.

I followed this blog post to create my custom function :

/// <summary>
/// Extend the Xslt transformation by adding new functions
/// </summary>
internal class ContentByQueryWebPartExXsltFunctions
    private static readonly Func<KeyValuePair<Guid, Guid>, string> displayFormGetter = FuncExtensions.Memoize(new Func<KeyValuePair<Guid, Guid>, string>((kp) =>
        var site = SPContext.Current.Site;
        using (var web = site.OpenWeb(kp.Key))
            var list = web.Lists[kp.Value];
            return list.DefaultDisplayFormUrl;

    public string GetDisplayUrl(string webId, string listId, int itemId)
        var webIdGuid = new Guid(webId);
        var listIdGuid = new Guid(listId);
        return displayFormGetter(new KeyValuePair<Guid, Guid>(webIdGuid, listIdGuid)) + "?ID=" + itemId;

internal static class FuncExtensions
    public static Func<A, R> Memoize<A, R>(this Func<A, R> f)
        var map = new Dictionary<A, R>();
        return a =>
            R value;
            if (map.TryGetValue(a, out value))
                return value;
            value = f(a);
            map.Add(a, value);
            return value;

I use Memoization to reduce the opening of multiple SPWeb objects.

Then, I inherited the ContentByQueryWebEx to exploit this functions :

public class ContentByQueryWebPartEx : ContentByQueryWebPart
    protected override void ModifyXsltArgumentList(ArgumentClassWrapper argList)
        var functions = new ContentByQueryWebPartExXsltFunctions();

        argList.AddExtensionObject("urn:ContentByQueryWebPartEx", functions);



Finally, I update my ItemStyle.xsl to register and use this new function :

      exclude-result-prefixes="x d xsl msxsl cmswrt"

    <xsl:template name="MyStyle"

        <xsl:variable name="DispFormUrl">
            <xsl:value-of select="cust:GetDisplayUrl(@WebId,@ListId,@ID)" />
        <a href="{$DispFormUrl}">Details</a>    


| improve this answer | |
  • Thanks Steve! I'm glad you used my blog post as a reference and very nice of you to put the link to it. Thanks again and good work! – Daniel Hinojo May 9 '13 at 16:51

In order to provide the link to the picture item instead of picture url, I recommend to modify SafeLinkUrl variable in ItemStyle.xsl that is used for Item Url:

 <xsl:variable name="SafeLinkUrl">
            <!--xsl:call-template name="OuterTemplate.GetSafeLink">
                <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
            <xsl:value-of select="concat($RootSiteRef,'/_layouts/CopyUtil.aspx?Use=id&amp;Action=dispform&amp;ItemId=',@ID,'&amp;ListId=',@ListId,'&amp;WebId=',@WebId,'&amp;SiteId=',$SiteId,'&amp;Source=',$Source)"/>

CopyUtil.aspx page

CopyUtil.aspx page is an application redirect page intended for redirection to the corresponding item or document.

The following parameters could be passed via URL:

  • Item ID
  • List ID
  • Web ID
  • Site ID
  • Source
  • List item
  • Action
  • InThisWeb
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.