Saturday, September 4, 2010

Sitecore Fetch Squad

Automated crawler fetching websites and blogs from Sitecore content

Archive for the ‘xslt’ Category

Get the HTML output of an XSLT rendering

Posted by admin On December - 29 - 2008
How to get the HTML output of an XSLT rendering.

Sitecore Code Snippets

Define XSLT rendering dynamically

Posted by admin On December - 29 - 2008
Define which XSLT rendering should be used on the page dynamically by using the XslTransform class.

Sitecore Code Snippets

Two useful tips for dtSearch customization in Sitecore

Posted by admin On December - 29 - 2008
dtSearch and Mixing Text Query
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.




Intranet” value=”Intranet” />

WebSite” value=”/index/” />
WebSite” valueWebSite/>

ExtranetSite” value=”/index/” />
ExtranetSite” value=”ExtranetSite” />

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 !

Posted by admin On December - 29 - 2008
Fyi -> speed problems could be caused by one single line in xslt ( impressive that you can kill a dual core P4 64bit 4Ghz with 8 GB mem in one single code line ).

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

Posted by admin On December - 29 - 2008
Webutils functions can be used as helper functions as well. In order to get the url of the server, we can use it as follows:

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

Posted by admin On December - 29 - 2008
It might be not obvious but is common practice to use util:GetString(string, default).

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

Posted by admin On December - 29 - 2008
Imagine a scenario where you have two or more content languages on a Sitecore solution. Some of them are regional and one is the global master language f.ex. in English.

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”

Posted by admin On December - 29 - 2008
A weird performance error has occurred in one of our solutions.

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

Posted by admin On December - 29 - 2008

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

Posted by admin On December - 29 - 2008

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>

 

 

 

Sitecore API