Assumptions
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.
Using Linq
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);
Using 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>);
Using XPath
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);
Using 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);
item.Axes.GetAncestors().Where(...)
to keep your code easy to understand and debug. – ImpactedAxes
property. – ScrutineerAxes
is generally my preferred way, when I remember that the property exists. Between the two of you I'm not sure which solution is better, so I upvoted you both and will keep an eye on this to accept an answer once more votes have been given. – Scrutineer