Valid for Sitecore 5.1.1
Evaluating XPath statement dynamically

Sitecore versions: tested with 5.1.1.21. Expected to work with 5.1.1.x.

The Problem:

We have a field in our item, named XPathExpression with value ="/sitecore/content/product".

We have the following lines in a XSLT file:

<xsl:variable name="expression" select="sc:field('XPathExpression',.)"/>
<xsl:for-each select="$expression">
...
Do something
...
</xsl:for-each>

We get the exception that $expression is a string and not a node-set.

Is there a way to get the item set from an Xpath expression dynamically in Sitecore?

The Solution:

In the case above we don't actually have an XPath statement but a Sitecore path which maps to a single item so you can get away with something more like:

<xsl:variable name="item" select="sc:item( sc:fld( 'XPathExpression',. ), . )"/>

This basically says "retrieve the Sitecore item (sc:item) from the current XML document (second .) which has the path or GUID identified by the XPathExpression field (sc:fld) in the context item (first .)".  It can be written more clearly at the expense of an extra variable something like:

<xsl:variable name="xpath" select="sc:fld( 'xpathexpression', . )" />
<xsl:variable name="item" select="sc:item( $xpath, . )"/>

It is reasonable to implement this field as type Tree which would store the GUID of the selected item rather than the path but the code would be the same either way.  This probably only works if the expression is a Sitecore path or GUID of a specific item, no predicates or anything else.

1.  Code for Implementing Extension in XSL

Here is sample code to use the extension (mostly taken from http://sdn.sitecore.net/Articles/XSL/Accessing%20Field%20Values/Multilist.aspx):

<xsl:variable name="xpath">.//*[@template='section']</xsl:variable>
<xsl:variable name="guids" select="test:EvaluateXPath( $home, $xpath )" />

<!--  GUIDS: <xsl:value-of select="$guids"/>-->

<xsl:call-template name="NextGuid">
  
<xsl:with-param name="ids" select="concat($guids,'|')"/>
</xsl:call-template>

<xsl:template name="NextGuid">
  
<xsl:param name="ids"/>
  
<xsl:if test="$ids">
    
<xsl:variable name="itm_id" select="substring-before($ids, '|')"/>
    
<xsl:if test="$itm_id">
      
<xsl:variable name="itm" select="sc:item($itm_id,.)"/>
      
<xsl:value-of select="sc:path( $itm )" />
      
<br />
    
</xsl:if>
    
<xsl:call-template name="NextGuid">
      
<xsl:with-param name="ids" select="substring-after($ids, '|')"/>
    
</xsl:call-template>
  
</xsl:if>
</xsl:template>

Using Xsl Extension Objects article describes how to implement XSL extensions.

2.  Sample XSL Extension

If it is required to process a real dynamic XPath then we should go for an XSL extension like the one shown below:

public Sitecore.Data.Items.Item GetItem( XPathNodeIterator xpni )
{
  xpni.MoveNext();
  
return( Sitecore.Context.Database.GetItem( xpni.Current.GetAttribute( "id", "" )));
}

public string EvaluateXPath( XPathNodeIterator xpni, string xpath )
{
  Sitecore.Xml.XPath.ItemNavigator nav
= Sitecore.Configuration.Factory.CreateItemNavigator(GetItem(xpni));
  XPathNodeIterator iter
= nav.Select( xpath );
  StringBuilder guids
= new StringBuilder();

  
while (iter.MoveNext())
  {
    guids.Append(iter.Current.GetAttribute(
"id", ""));
    guids.Append(
"|");
  }

  
return( guids.ToString().Trim( '|' ));
}

Note that the code above returns a pipe-separated list of GUIDs