XSLT FAQ

Fetching data in XSLTs using inline C#

How can I get more fine-grained control over database queries and the XML it generates?

Answer:

You can use “the power of LINQ” to do advanced queried in C1 by adding inline C# functions to your XSLT – it’s not very complicated given a simple sample – see below or download Fetching data in XSLTs using inline CSharp.xslt.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl in msxsl csharp"
	xmlns:in="http://www.composite.net/ns/transformation/input/1.0"
	xmlns:msxsl="urn:schemas-microsoft-com:xslt"
	xmlns:csharp="http://c1.composite.net/sample/csharp"	
	xmlns="http://www.w3.org/1999/xhtml">
 
	<xsl:template match="/">
		<html>
			<head />
			<body>
				<textarea>
					<xsl:copy-of select="csharp:GetLatestPages(5)" />
				</textarea>
			</body>
		</html>
	</xsl:template>

 <msxsl:script implements-prefix="csharp" language="C#">
	<msxsl:assembly name="System.Core"/>
	<msxsl:assembly name="System.Xml.Linq"/>
	<msxsl:assembly name="Composite"/>
	<msxsl:assembly name="Composite.Generated"/>

 	<msxsl:using namespace="System.Collections.Generic"/>
 	<msxsl:using namespace="System.Linq"/>
 	<msxsl:using namespace="System.Xml.Linq"/>
 	<msxsl:using namespace="Composite.Data"/>

 	<![CDATA[
	    public static XPathNodeIterator GetLatestPages(int maxItemsToReturn)
	    {
	        using (DataConnection connection = new DataConnection())
	        {
	            IEnumerable<XElement> pageElements =
	                from dataItem in connection.Get<Composite.Data.Types.IPage>()
	                orderby dataItem.ChangeDate descending

	                select new XElement("Pageinfo",
	                    new XAttribute("Title", dataItem.Title),
	                    new XAttribute("ChangeDate", dataItem.ChangeDate),
	                    new XAttribute("Description", dataItem.Description));

	            XElement result = new XElement("Result",
	                pageElements.Take(maxItemsToReturn));

	            return result.CreateNavigator().Select("/Pageinfo");
	        }
	    }
	]]>
 </msxsl:script>

</xsl:stylesheet>

Download the source

The C# code should be wrapped in a <![CDATA[ ... ]]> block - this will allow for free use of otherwise XML reserved characters. Below the C# code is shown by itself.

public static XPathNodeIterator GetLatestPages(int maxItemsToReturn)
{
    using (DataConnection connection = new DataConnection())
    {
        IEnumerable<XElement> pageElements = 
            from dataItem in connection.Get<Composite.Data.Types.IPage>()
            orderby dataItem.ChangeDate descending
            select new XElement("Pageinfo", 
            new XAttribute("Title", dataItem.Title), 
            new XAttribute("ChangeDate", dataItem.ChangeDate), 
            new XAttribute("Abstract", dataItem.Description));

        XElement result = new XElement("Result", pageElements.Take(maxItemsToReturn));
        return result.CreateNavigator().Select("/Pageinfo");
    }
}

The sample above will generate <PageInfo /> elements based on the 5 most recently updates pages and select some data from them. The data fetching is done using C# and C1’s super intuitive DataConnection. Performance is good and the preview pane will contain helpful error messages if there are errors in the C# code - and when it runs OK the preview gives you instant feedback on your code change.

To run the sample, do the following:

You should note the following about the sample:

  • This sample requires that the file /bin/Composite.Generated.dll exists. If this isn’t the case, remove the line <msxsl:assembly name="Composite.Generated"/>.
  • The namespace http://c1.composite.net/sample/xslt/csharp is an arbitrary URI – change it to something which identifies you, so the author (company) can be identified.
  • The function csharp:GetLatestPages(5) is calling our C# code – in this sample we just do a raw copy of the XML returned from C#, so we can see it in the preview right away.
  • Inside the <msxsl:script /> block, we define assemblies to load (DLL references), namespaces we are using and the actual C# function.
  • If the line <msxsl:assembly name="Composite.Generated"/> is present, you can reference any dynamic data type in the system.
  • connection.Get<Composite.Data.Types.IPage>() define what type of data we want. The sample grabs IPage data – change the full name of the type to the type you want data from.
  • You can easily change ordering. Note that in dataItem.ChangeDate the ChangedDate part is the name of a field on a data type.
  • descending should be self-explanatory
  • The XElement part is what defines the “XML template” for the data we are retrieving.
  • pageElements.Take(maxItemsToReturn) is what actually “executes” the data fetching– we are asking it to fetch (maximum) 5 IPage data records, read only 3 of the fields and then wrap this data it in the XML template defined above.
  • Finally we convert our XElements into something the XSLT processor can work with and return it.

To modify this to another data type, do the following:

  • Change the namespace declaration (http://c1.composite.net/sample/xslt/csharp)
  • Change the data type (Composite.Data.Types.IPage)
  • Change the ordering field name
  • Change the field names used the create the XAttributes
  • Change the element name of the XElement ("Pageinfo")