Query your datasource using custom tokens in Sitecore

Before heading into the post I would like to thank Sitecore for giving me the great honor of being awarded as one of the 167 MVPs. I truly enjoy sharing my experiences with people so this means a lot to me. Check out all the skilled MVPs at Sitecore MVPs 2015


I would like to show you guys how to do queryable datasources for your renderings. This is nothing new and there are a lot of posts out there describing it very well, so why reinvent the wheel? I found some really nice posts and used most of their code.
Queries in Datasource location on Sitecore Layouts by Thomas Stern aka Dr Stern 🙂
Multiple Datasource Locations using Queries are back in Sitecore 7.2 Update-2 by Sean Holmesby

As Sean pointed out in his post – Since Sitecore 7.2 you can have multiple datasources, that is really cool.

Sitecore 7.2 Update-2 fixes this, and Sitecore’s default code will allow you to define multiple Datasource locations by having them pipe separated in the ‘Datasource Location’ field on a rendering/sublayout

I checked Sean’s and Thomas code and created my pipeline for supporting queryable datasources to the renderings. I started out doing some queries and it worked great but then I needed to to go “above” my site node to find its datasource folder.

—Datasource content
——-Some folder

In other words I need to get the name of an element and then add it to the datasource path, something like this:

query:./ancestor-or-self::*[@@templatename='Site']/../Datasource content/*[@@name=name of site element])/Some folder

I read all kinds of stuff on what you can do with the query using XPath functions. Here are some good posts you should read:
Querying Items from Sitecore

Good old Sitecore SDN stuff:
Sitecore Query Syntax
Data Definition Reference – chapter 4:3
Using Sitecore Fast Query

At the end I came to the conclusion that I needed following XPath function:
name(node) – XPath, XQuery, and XSLT Functions, unfortunately this one is not supported in Sitecore’s XPath

So what to do? Why not make a custom token since I already have my own pipeline for the queryable datasource. The custom token should be something like this:

<< node?Field attribute >> 

I found this nice old post about accessing special properties of a Sitecore item the same way you get a typical field’s value:
Getting a special field value in Sitecore by Sean Kearney

Here is how the datasource finally will look like:

/sitecore/content/Datasource content/Global/Social sharing|query:./ancestor-or-self::*[@@templatename='Site']/../Datasource content/*[@@name=<<ancestor-or-self::*[@@templatename='Site']?@name>>])/Social sharing

Here is the code for the pipeline:

public class MultipleDataSourceLocationsWithQueries
    private IDatasourceQueryService _datasourceQueryService; 

    public void Process(GetRenderingDatasourceArgs args)
        Assert.IsNotNull(args, "args");

        this._datasourceQueryService = new DatasourceQueryService(args.ContextItemPath, args.ContentDatabase, args.RenderingItem["Datasource Location"], args.DatasourceRoots);

        if (!this._datasourceQueryService.IsQueryInDataSourceLocation()) 


Then I created a service for the datasource stuff.

public class DatasourceQueryService : IDatasourceQueryService
    private readonly string _contextItemPath;
    private readonly Database _contentDatabase;
    private readonly string _datasourceLocation;
    private readonly List<Item> _datasourceRoots;
    private readonly Regex _regEx;

    public DatasourceQueryService(string contextItemPath, Database contentDatabase, string datasourceLocation, List<Item> datasourceRoots)
        this._contextItemPath = contextItemPath;
        this._contentDatabase = contentDatabase;
        this._datasourceLocation = datasourceLocation;
        this._datasourceRoots = datasourceRoots;
        this._regEx = new Regex(GetRegexPattern());

    public bool IsQueryInDataSourceLocation()
        return this._datasourceLocation.Contains(QueryIdentifier);

    public void ProcessQuerys()
        ListString possibleQueries = new ListString(this._datasourceLocation);
        foreach (string possibleQuery in possibleQueries)
            if (possibleQuery.StartsWith(QueryIdentifier))

    private string GetRegexPattern()
        return String.Format(".*{0}(.*){1}.*", SpecialStartItemDelimiter, SpecialEndItemDelimiter);

    private void ProcessQuery(string query)
        //Remove the "query:."
        query = query.Replace(QueryIdentifier, "");

        Item[] datasourceLocations = ResolveDatasourceRootFromQuery(query);

        if (datasourceLocations == null || !datasourceLocations.Any()) 

        foreach (Item dataSourceLocation in datasourceLocations.Where(dataSourceLocation => !this._datasourceRoots.Exists(item => item.ID.Equals(dataSourceLocation.ID))))

    private Item[] ResolveDatasourceRootFromQuery(string queryPath)
        Match matchedData = this._regEx.Match(queryPath);

        int numberOfMatchedTokens = 1;

        while (matchedData.Success)
            //Just in case - I hate while loops
            if (numberOfMatchedTokens > MaxNumberOfIterations)
            queryPath = GenerateQueryPathForSpecialToken(matchedData, queryPath);
            matchedData = this._regEx.Match(queryPath);


        return GetItemsFromQuery(queryPath);

    private string GenerateQueryPathForSpecialToken(Match matchedData, String queryPath)
        string specialQueryPath = matchedData.Groups[1].ToString();

        string translatedValue = ResolveSpecialItemInQuery(specialQueryPath);

        return queryPath.Replace(
            string.Format("{0}{2}{1}", SpecialStartItemDelimiter, SpecialEndItemDelimiter, specialQueryPath),

    private Item[] GetItemsFromQuery(string queryPath)
            return this._contentDatabase.SelectItems(string.Format("{0}/{1}", this._contextItemPath, queryPath));
        catch (Exception ex)
            Log.Error(String.Format(@"Datasource query was not valid:{0}", queryPath), ex, this);
            return null;

    private string ResolveSpecialItemInQuery(string specialQueryPath)
        if (!specialQueryPath.Contains(FieldDelimiter))
            return string.Empty;

        string specialItemPath = specialQueryPath.Split(char.Parse(FieldDelimiter))[0];

        if (string.IsNullOrWhiteSpace(specialItemPath))
            return string.Empty;

        Item[] specialItems = GetItemsFromQuery(specialItemPath);

        if (!specialItems.Any())
            return string.Empty;

        string fieldProperty = specialQueryPath.Split(char.Parse(FieldDelimiter))[1];

        if (string.IsNullOrWhiteSpace(fieldProperty))
            return string.Empty;

        return specialItems.Select(item => item[fieldProperty]).FirstOrDefault();


    private const string QueryIdentifier = "query:.";
    private const string SpecialStartItemDelimiter = "<<";
    private const string SpecialEndItemDelimiter = ">>";
    private const string FieldDelimiter = "?";
    private const Int32 MaxNumberOfIterations = 10;


The interface for the service

public interface IDatasourceQueryService
    bool IsQueryInDataSourceLocation();

    void ProcessQuerys();

In order to make the pipeline work we need to do a patch config file.

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
       <processor type="Sandbox.QueryableDatasource.Pipelines.GetRenderingDatasource.MultipleDataSourceLocationsWithQueries, Sandbox.QueryableDatasource"
                   patch:after="processor[@type='Sitecore.Pipelines.GetRenderingDatasource.GetDatasourceLocation, Sitecore.Kernel']" />

That’s all for now folks 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.