I'm attempting to expand upon a custom Sitecore command to determine if the current item has a parent item matching a certain template id.
I know the query should ideally be as simple as ./ancestor::*[@@templateid='{26710865-F082-4714-876B-D5E1F386792F}']
if the item is the context, or /sitecore/content/home/full/path/to/the-item/ancestor::*[@@templateid='{26710865-F082-4714-876B-D5E1F386792F}']
Unfortunately the item path includes dashes which need to be escaped like /sitecore/content/home/full/path/to/#the-item#/ancestor::*[@@templateid='{26710865-F082-4714-876B-D5E1F386792F}']
.
However, ideally I'd like to just use the full path of the item, since it's available as item.Paths.FullPath
.
Given an item, what's the best way to write a query containing it's full path, and escaping any dashes that might be contained within?
I've never seen any Sitecore util class or any other out of the box code which does what you need. It's funny that Sitecore does have a util method which returns false
(yes, it does return false
) but doesn't have a method which escapes item path so it can be used in query.
You may find code which does what you want (written by Anders Laub) here: https://blog.istern.dk/2014/10/29/escaping-dashes-in-sitecore-queries-datasource-query-update/
And if you're too lazy to click the link, I've copied to code here:
private string EscapeItemNamesWithDashes(string queryPath)
{
if (!queryPath.Contains("-"))
return queryPath;
var strArray = queryPath.Split(new char[] { '/' });
for (int i = 0; i < strArray.Length; i++)
{
if (strArray[i].IndexOf('-') > 0)
strArray[i] = "#" + strArray[i] + "#";
}
return string.Join("/", strArray);
}
If you want to escape also space character, you can try this regex:
string escapedPath = Regex.Replace(myItem.Paths.FullPath, "[^/]*[- ][^/]*", "#$0#");
Also you should remember that there are some reserved words in Sitecore which should be escaped as well. Those are (copied from http://www.newguid.net/sitecore/2012/escape-characterswords-in-a-sitecore-query/ ):
Assuming you have a reference to a Sitecore.Data.Items.Item
(called item
) and you would like to find an ancestor with a given Sitecore.Data.ID
(called id
), there are a number of ways you can access the ancestor.
In a typical Sitecore setup without any custom libs, I would typically use a bit of Linq so as to avoid encoding issues in XPath.
ancestor =
item
.Axes
.GetAncestors()
.FirstOrDefault(ancestor => ancestor.TemplateID == id);
Closest
I use a bespoke framework for Sitecore development that involves a wide variety of extension methods and customized item generation. To avoid the overhead of accessing all the ancestors before filtering, I would use the Closest
extension method:
public static Item Closest(this Item source, Func<Item, bool> test)
{
Item cur;
for (cur = source; cur != null; cur = cur.Parent)
if (test(cur))
break;
return cur;
}
Accessing the ancestor would then be:
ancestor =
item
.Closest(ancestor => ancestor.TemplateID == id);
(Actually, I typically use code that looks like)
ancestor = (ITemplateNameItem) item.Closest(Is.Type<ITemplateNameItem>);
I usually avoid XPath and only use it as a tool of last resort because it often makes code harder to read, introduces encoding issues such as the one you're faced with in this question, and has a hard limit on the number of items that can be returned.
That said, Sitecore has many tools available for searching with XPath, and in some circumstances it does simplify things.
The trick to fixing item paths that contain spaces is: Don't use item paths.
Instead, you can safely use the item's ID, with no more context necessary because it's an absolute reference to the item. It's also guaranteed to follow a specific format.
var query =
string.Format(
"//{0}/ancestor::*[@@templateid='{1}']",
item.ID.ToString(),
id.ToString());
/* alternatively
var query =
string.Format(
"{0}/ancestor::*[@@templateid='{1}']",
item.Paths.LongID,
id.ToString());
*/
ancestor =
item
.Database
.SelectSingleItem(query);
Sitecore.Data.Query.Query
As I mentioned previously, Sitecore has many tools available for searching with XPath. One of these tools is Sitecore.Data.Query.Query
. The SelectItems
and SelectSingleItem
methods have additional optional parameters, one of which is a Sitecore.Data.Items.Item
as a contextNode
.
Passing an item in as the second parameter uses the item as the context for the XPath query.
var query =
string.Format(
"./ancestor::*[@@templateid='{0}']",
id.ToString());
ancestor =
Sitecore
.Data
.Query
.Query
.SelectSingleItem(query, item);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With