Can I programmatically avoid dashes in Sitecore queries using FullPath?

I am trying to extend the Sitecore custom command to determine if the current element has a parent element that matches a specific template identifier.

I know that, ideally, the request should be as simple as ./ancestor::*[@@templateid='{26710865-F082-4714-876B-D5E1F386792F}'] if the element is a context, or /sitecore/content/home/full/path/to/the-item/ancestor::*[@@templateid='{26710865-F082-4714-876B-D5E1F386792F}']

Unfortunately, the element path includes hyphens that must be escaped as /sitecore/content/home/full/path/to/#the-item#/ancestor::*[@@templateid='{26710865-F082-4714-876B-D5E1F386792F}'] .

However, ideally, I would just like to use the full path to the item, as it is available as item.Paths.FullPath .

Given the element, what is the best way to write a query containing the full path and avoid any dashes that may be contained inside?

+7
sitecore sitecore7
source share
4 answers

Assumptions

Assuming you have a link to Sitecore.Data.Items.Item (called item ), and you would like to find the ancestor with the given Sitecore.Data.ID (called id ), there are several ways to access the ancestor.

Using Linq

In a typical Sitecore setup without any custom libs, I would normally use the Linq bit to avoid coding problems in XPath.

 ancestor = item .Axes .GetAncestors() .FirstOrDefault(ancestor => ancestor.TemplateID == id); 

Using Closest

I use a special sitecore development framework that includes a wide range of extension methods and personalized element creation. To avoid the overhead of accessing all 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; } 

Access to the ancestor will be as follows:

 ancestor = item .Closest(ancestor => ancestor.TemplateID == id); 

(Actually, I usually use code that looks)

 ancestor = (ITemplateNameItem) item.Closest(Is.Type<ITemplateNameItem>); 

Using XPath

I usually avoid XPath and use it only as a last resort, because it often makes the code harder to read, introduces encoding problems like the one you encountered in this question, and has a hard limit on the number of elements that can be returned.

However, Sitecore has many tools for searching with XPath, and in some cases it makes it easier.

Trick to fix paths of elements containing spaces: Do not use element paths.

Instead, you can safely use the element identifier without the need for more context, because it is an absolute reference to the element. It also guarantees the execution of 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 earlier, Sitecore has many search tools in XPath. One of these tools is Sitecore.Data.Query.Query . The SelectItems and SelectSingleItem have additional optional parameters, one of which is Sitecore.Data.Items.Item as contextNode .

Passing an element as the second parameter uses this element as the context for the XPath request.

 var query = string.Format( "./ancestor::*[@@templateid='{0}']", id.ToString()); ancestor = Sitecore .Data .Query .Query .SelectSingleItem(query, item); 
+5
source share

I have never seen a single Sitecore util class or any other code that does what you need. It's funny that Sitecore has a util method that returns false (yes, it returns false ), but it doesn’t have a method that avoids the element path, so it can be used in the request.

You can find the code that 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 are too lazy to click the link, I copied the 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 avoid the space character, you can try this regex:

 string escapedPath = Regex.Replace(myItem.Paths.FullPath, "[^/]*[- ][^/]*", "#$0#"); 

You should also remember that Sitecore has reserved words that must also be escaped. This (copied from http://www.newguid.net/sitecore/2012/escape-characterswords-in-a-sitecore-query/ ):

  • ancestor
  • and
  • child
  • descendant
  • Div
  • False
  • Following
  • mod
  • or
  • parent
  • preceding
  • independently
  • True
  • exclusive
+3
source share

Sitecore does not have a public helper method that avoids Sitecore request paths. You will need to implement the accelerating logic manually.

Code Approach:

I found the code in Sitecore.Kernel.dll in the Sitecore.Pipelines.GetLookupSourceItems.ProcessDefaultSource pipeline processor. I had to rework it so that complex selectors containing : and [...] would not escape:

 static string EscapeQueryPath(string queryPath) { string[] strArray = queryPath.Split('/'); for (int i = 0; i < strArray.Length; ++i) { string part = strArray[i]; if ((part.IndexOf(' ') >= 0 || part.IndexOf('-') >= 0) && part.IndexOf(':') == -1 && part.IndexOf('[') == -1 && !part.StartsWith("#", StringComparison.InvariantCulture) && !part.EndsWith("#", StringComparison.InvariantCulture)) { strArray[i] = '#' + part + '#'; } } return string.Join("/", strArray); } 

Please note that this algorithm:

  • Idempotent - he will not be able to avoid parts of the path that have already been escaped, so /#item-name#/ will not turn into /##item-name##/ .
  • Holds the names of elements that contain either hyphens or spaces.
  • Takes into account complex selectors (for example, ancestor::*[...] in your example).

Regular Expression Approach:

Here is another escape approach. It will have exactly the same results as the code above.

 string path = "./my-item/ancestor::*[@@templateid='{26710865-F082-4714-876B-D5E1F386792F}']"; string result = Regex.Replace(str, "/([^/#\\[\\:]*[- ][^/#\\[\\:]*(?=($|/)))", "/#$1#"); // result: ./#my-item#/ancestor::*[@@templateid='{26710865-F082-4714-876B-D5E1F386792F}'] 

This is shorter, but most likely a little slower.

+2
source share

I agree with the previous answers, but there are a few things to avoid for queries - names with the words "or" and "and" and words starting with numbers. I used code similar to this:

 string _path = "/path/to-item/12name and qwe/test"; // your path string[] pathParts = _path.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries); string escapedPath = string.Join("/", pathParts.Select(p => { if (p.Contains("and") || p.Contains("or") || p.Contains("-") || char.IsDigit(p[0])) { return "#" + p + "#"; } return p; })); 
0
source share

All Articles