Archive for the ‘xslt’ Category
Get the HTML output of an XSLT rendering
Define XSLT rendering dynamically
Sitecore Code Snippets
Two useful tips for dtSearch customization in Sitecore
In dtSearch when I search with multiple words its always exact match search. For example:
If I write query “Product Foobar”. When in my page there is text “Foobar Product”.
Solution:
But dtSearch has the following search options defined:
public enum Options
{
AllWords = 2,
AnyWords = 4,
CaseSensitive = 8,
ExactPhrase = 1,
Logic = 0×20,
Ranked = 0×40,
WildCards = 0×10
}
To use these options, you should create the custom xslt extension which will return Sitecore.Modules.Search.dtSearch.Search(searchString, Sitecore.Modules.Search.Options.AllWords)
Multiple indexes
Sometimes you might have multiple sites on same installation of the Sitecore and you want search index also be separated to each sites.
For example if you Sitecore content tree looks like:
Intranet
WebSite
ExtranetSite
Then create normally separate indexes in dtSearch indexer on the server and add the following lines in the web.config file.
You of course need XSL helper or custom function below to switch between sites
private string GetSearchResultIndex(string dist)
{
string searchText = txbSearch.Text;
// Instantiate the Search Engine
ISearch engine = Sitecore.Modules.Search.Factory.CreateSearchEngine();
// Get the dtSearch engine implementation
dtSearch your_dtSearch = engine as dtSearch;
// Set index
string pathIndex = Server.MapPath(pathIndexDtSearch(dist) + nameIndexDtSearch(dist) + “\”);
your_dtSearch.Index = pathIndex;
// Execure search
your_dtSearch.SearchTextOptions(searchText, Options.AllWords);
// Get search resalts as XML
System.Xml.XmlDocument searchResult = your_dtSearch.SearchResults;
// Format result
string result = string.Empty;
System.Xml.XmlNodeList list = searchResult.SelectNodes(”/sitecore/result/item”);
foreach(System.Xml.XmlNode node in list)
{
string url = node.SelectSingleNode(”url”).InnerText;
result += “” + url + “
“;
}
return result;
}
The Sitecore Experience
Sitecore performance - xslt NONO !
Never compare nodeset´s unless you really have to .. what you typically need is to figure out if current node is thye same as home node … do NOT do like this :
xsl:if test=”$home=$sc_current” …. < -- no no no .. verboten !!!! STOP !
The line above will loop all nodes under $home and compare every node with every node in $sc_currentitem.
Ofcourse what you DO want to do is :
xsl:if test=”$home/@id=$sc_current/@id
If you experience speed problems, this could be why !
The Sitecore Experience
using Sitecore.Kernel.Webutils
install it in web.config:
<xslExtensions>
…
<extension mode=”on” type=”Sitecore.Web.WebUtil, Sitecore.Kernel” namespace=”http://www.sitecore.net/webutil” singleInstance=”true” />
</xslExtensions>
declare it in your xslt:
xmlns:webutil=”http://www.sitecore.net/webutil”
then use it (example from a “print page” footer):
<xsl:text>Artiklens placering: </xsl:text><xsl:value-of select=”webutil:GetServerUrl()” /><xsl:value-of select=”sc:path(.)” />
The Sitecore Experience
util:GetString
A xsl:choose used to display the title of an item can be replaced as follows:
<xsl:choose>
<xsl:when test=”sc:fld(’menutitle’,.)”>
<xsl:value-of select=”sc:fld(’menutitle’,.)”>
</xsl:when>
<xsl:when test=”sc:fld(’title’,.)”>
<xsl:value-of select=”sc:fld(’title’,.)”>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select=”./@name”>
</xsl:otherwise>
</xsl:choose>
simpler call:
<xsl:value-of select=”util:GetString(util:GetString(sc:fld(’title’,.), sc:fld(’menutitle’,.)),@name)”/>
The Sitecore Experience
Fallback to a Master Language
When new documents are created in the master language they must be translated to the local language. But as this workflow process might take time it could be nice to be able to show the master language version on the local site until translation is done.
To obtain that you need to be able to show content from any language when doing renderings. Using C# based renderings that is a simple task as the Sitecore object model exposes methods for retrieving field data from a specified language. That is not the case in XSLT renderings where the commonly used sc:fld method does not take a language parameter but assumes the current language as set in the State object.
To expose such a function a new XSLT helper could be created with the following function that has the missing parameter.
public string fld(string sFieldName, XPathNodeIterator ni, string language)
{
string itemID = ni.Current.GetAttribute(”id”,”");
IWebItem currentItem = WebFactory.GetItem(itemID);
return currentItem.GetFieldValue(sFieldName,language);
}
This allows the XSLT designer to start by requesting the local language using the XSLT parameter $lang as input. If it returns empty the master language identifier can the be used instead.
The master language could also be specified in web.config and the switch could then be implemented directly in the new XSLT helper function without any need for requesting the language parameter from the user. Like this:
public string fld(string sFieldName, XPathNodeIterator ni)
{
string itemID = ni.Current.GetAttribute(”id”,”");
IWebItem currentItem = WebFactory.GetItem(itemID);
string sFieldValue = currentItem.GetFieldValue(sFieldName);
if(sFieldValue==””)
{
sFieldValue = currentItem.GetFieldValue(sFieldName,Settings.GetSetting(”Masterlanguage”);
}
Return sFieldValue;
}
Ideas for further features: The function could be extended for retrieval of sub values and the Masterlanguage setting could be a pipe separated list of prioritized fallback languages.
/Pau
The Sitecore Experience
XSLT performance issue using “contains”
The following line of XSLT takes up to 1 second to execute:
<xsl:if test=”$start/item[contains($templates,concat('!',@template,'!'))] != ””>
- $templates contains a string like “!rootfolder!folder!document!externalmenulink!”
- @template contains a string like “rootfolder”
- The number of items under $start is less than 10
This should not be a hard task and it is not in most cases. In a for-each loop with changing @template and $start values only some calls are slow. Others execute in less than a millisecond. And the fast ones in some cases have the exact same @template value as the slow ones - and even more items under $start to check.
One could imagine that this behavior was related to other elements stressing the server. But as the same four calls fails every time the error must be related to them in someway. They must have some common characteristics. I just have not been able to identify those!
But I did find out that modifying the test attribute to
<xsl:if test=”count($start/item[contains($templates,concat('!',@template,'!'))]) != ‘0′”>
…solved the problem! Every call now executes in less than a millisecond.
As the functionality is exactly the same I strongly recommend using the later even though the problem does not occur in general when using the other.
The Sitecore Experience
XSLT security
In V5.3 it is possible to completely disable security for all descendants of WebControl (including XslFile). Simply set the property ‘DisableSecurity’ to ‘true’ on the control.
For XSLT files, we have created two new XSL controls that can be used to enable and disable security for specific sections in an XSLT file.
An example is provided below:
<xsl:template match="*" mode="main">
<h2>Security enabled</h2>
<sc:enableSecurity>
<xsl:for-each select="item">
Child <xsl:value-of select="position()"/><br/>
<sc:text field="@name"/><br/>
<br/>
</xsl:for-each>
</sc:enableSecurity>
<h2>Security disabled</h2>
<sc:disableSecurity>
<xsl:for-each select="item">
Child <xsl:value-of select="position()"/><br/>
<sc:text field="@name"/><br/>
<br/>
</xsl:for-each>
</sc:disableSecurity>
</xsl:template>
The <sc:enableSecurity> surrounds its containing statements with a
Context.Security.EnterState(SecurityState.Enabled) and a Context.Security.ExitState().
The <sc:disableSecurity> surrounds its containing statements with a
Context.Security.EnterState(SecurityState.Disabled) and a Context.Security.ExitState().
After preprocessing, the code will look like this:
<xsl:template match="*" mode="main">
<h2>Security enabled</h2>
<xsl:if test="true()">
<xsl:value-of select="sc:EnterSecurityState(true())" />
<xsl:for-each select="item">
Child <xsl:value-of select="position()" /><br />
<xsl:value-of select="sc:fld(‘@name’, .)" disable-output-escaping="yes" />=
<xsl:value-of select="sc:fld(’title’, .)" disable-output-escaping="yes" /><br /><br /></xsl:for-each>
<xsl:value-of select="sc:ExitSecurityState()" />
</xsl:if>
<h2>Security disabled</h2>
<xsl:if test="true()">
<xsl:value-of select="sc:EnterSecurityState(false())" />
<xsl:for-each select="item">
Child <xsl:value-of select="position()" /><br />
<xsl:value-of select="sc:fld(‘@name’, .)" disable-output-escaping="yes" />=
<xsl:value-of select="sc:fld(’title’, .)" disable-output-escaping="yes" /><br /><br /></xsl:for-each>
<xsl:value-of select="sc:ExitSecurityState()" />
</xsl:if>
</xsl:template>

Sitecore API
Cache sizes
In Sitecore 5.1 we go from having one large cache (mapping to the ASP.NET cache) to using multiple custom caches.
The caches are all accessed through a common class, the CacheManager. This class has a lot of methods used for adding/removing data and performing other cache related functions.
Database caches
The credential cache stores information about user rights. For instance, when it has been determined that a specific user can or can not read a given item, this information is stored in the credential cache. Subsequent read requests can then be granted without requiring a full security scan for the user again.
The data cache stores data read from the data provider(s). The data is stored in a format that makes it very fast to access. Specifically, the cache contains objects of the type DataManager.DataContainer.
The path mapping cache stores information about previously resolved paths. For instance, if the system has already determined that the path "/sitecore/content/home" maps to the ID {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} it stores this information. The next time someone requests an item using the same path, the item can be retrieved very fast using the cached ID.
Site caches
The html cache stores the html output of renderings that have been set to Cacheable.
The xsl cache is used for storing compiled XSLT files in memory. This relieves the system from the need to recompile the XSLT’s every time they are needed. Also, it helps keep memory consumption down when using inline code in XSLT’s (as these can not be unloaded due to a limitation in .Net).
The registry cache is used by the Sitecore Client to store various user settings and would not normally be used by other applications.
The viewState cache is also an interal cache used by the Sitecore Client.
Cache sizes
Cache sizes can be set up either on a specific site or database definition or it can be specified in the <cacheSizes> section. The values set directly on a site or a database will always take precedence over the values set in <cacheSizes>.
The <cacheSizes> section should pretty much be self-explanatory. An example is shown below.
<cacheSizes>
<databases>
<core>
<data>10MB</data>
<credential>1MB</credential>
<pathMapping>1MB</pathMapping>
</core>
</databases>
<sites>
<core>
<html>0</html>
<registry>10MB</registry>
<viewState>0</viewState>
<xsl>0</xsl>
</core>
<website>
<html>10MB</html>
<registry>0</registry>
<viewState>0</viewState>
<xsl>5MB</xsl>
</website>
</sites>
</cacheSizes>
The valid cache names for the <databases> element are:
data
credential
pathMapping
The valid cache names for the <sites> element are:
html
registry
viewstate
xsl
To set a cache size directly on a site, use an attribute named xxxCacheSize where xxx is the name of the cache. For instance, to set the size of the html cache on the web site use:
<site name="website"
…
htmlCache="10MB" />
The size can be specified in bytes (no postfix), kilobytes (KB) or megabytes (MB). Spaces and dots are allowed in the value string, so the following is also valid:
<site name="website"
…
htmlCache="1.024 KB" />
To set a cache size directly on a database, you must use the properties on the database object (as the database object is constructed by Sitecore.Factory using only reflection).
To set the size of the data cache on the "master" database you can use:
<database id="master" …>
…
<caches.DataCache.MaxSize>1000000</caches.DataCache.MaxSize>
</database>
Note that the size must be specified in bytes (as the type of the MaxSize property is long).
Disable caching
By settting a size of 0 (zero) on a cache, the cache in question will be disabled. For instance, to disable html caching on the web site:
<site name="website"
…
htmlCache="0" />
To disable all caching whatsoever in the system, the global setting "Caching.Enabled" can be used like this:
<setting name="Caching.Enabled" value="false" />
This setting is mostly for diagnostic purposes.
As a side note, individual data providers may also prevent their data from being cached by using the CacheOptions property on the DataProvider base class. For an example of this, see the file system data provider, which is defined like this in web.config:
<filesystem
type="Sitecore.Data.DataProviders.FileSystemDataProvider,
Sitecore.Kernel">
<CacheOptions.DisableAll>true</CacheOptions.DisableAll>
</filesystem>

