Help me, Stackoverflow!
I have a simple .NET 3.5 console app that reads some data and sends emails. I'm representing the email format in an XSLT stylesheet so that we can easily change the wording of the email without needing to recompile the app.
We're using Extension Objects to pass data to the XSLT when we apply the transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:EmailNotification="ext:EmailNotification">
-- this way, we can have statements like:
<p>
Dear <xsl:value-of select="EmailNotification:get_FullName()" />:
</p>
The above works fine. I pass the object via code like this (some irrelevant code omitted for brevity):
// purely an example structure
public struct EmailNotification
{
public string FullName { get; set; }
}
// Somewhere in some method ...
var notification = new Notification("John Smith");
// ...
XsltArgumentList xslArgs = new XsltArgumentList();
xslArgs.AddExtensionObject("ext:EmailNotification", notification);
// ...
// The part where it breaks! (This is where we do the transformation)
xslt.Transform(fakeXMLDocument.CreateNavigator(), xslArgs, XmlWriter.Create(transformedXMLString));
So, all of the above code works. However, I wanted to get a little fancy (always my downfall) and pass a collection, so that I could do something like this:
<p>The following accounts need to be verified:</p>
<xsl:for-each select="EmailNotification:get_SomeCollection()">
<ul>
<li>
<xsl:value-of select="@SomeAttribute" />
</li>
</ul>
<xsl:for-each>
When I pass the collection in the extension object and attempt to transform, I get the following error:
"Extension function parameters or return values which have Clr type 'String[]' are not supported."
or List, or IEnumerable, or whatever I try to pass in.
So, my questions are:
How can I pass in a collection to my XSLT?
What do I put for the xsl:value-of select="" inside the xsl:for-each ?
Is what I am trying to do impossible?
Edit: After I saw the two answers below, I took Chris Hynes' code and modified it very slightly to suit my needs. Solution is as follows:
// extension object
public struct EmailNotification
{
public List<String> StringsSetElsewhere { private get; set; }
public XPathNavigator StringsNodeSet
{
get
{
XmlDocument xmlDoc = new XmlDocument();
XmlElement root = xmlDoc.CreateElement("Strings");
xmlDoc.AppendChild(root);
foreach (var s in StringsSetElsewhere)
{
XmlElement element = xmlDoc.CreateElement("String");
element.InnerText = s;
root.AppendChild(element);
}
return xmlDoc.CreateNavigator();
}
}
}
And in my XSLT ...
<xsl:for-each select="EmailNotification:get_StringsNodeSet()//String">
<ul>
<li>
<xsl:value-of select="." />
</li>
</ul>
</xsl:for-each>
Worked perfectly!