c# - paginas - Objetos de extensión.NET con XSLT: ¿cómo iterar sobre una colección?
extensiones de dominio y su significado (2)
El XSLT para cada uno espera que un conjunto de nodos se repita: no puede pasar directamente una matriz desde su código C #. Debería devolver un XPathNodeIterator.
Algo como esto:
public static XPathNodeIterator GetSomeCollection()
{
XmlDocument xmlDoc = new XmlDocument();
string[] stringsToReturn = new string[] { "String1", "String2", "String3" };
XmlElement root = xmlDoc.CreateElement("Strings");
xmlDoc.AppendChild(root);
foreach (string s in stringsToReturn)
{
XmlElement el = xmlDoc.CreateElement("String");
el.InnerText = s;
root.AppendChild(el);
}
XPathNodeIterator xNodeIt = xmlDoc.CreateNavigator().Select(".");
return xNodeIt;
}
¡Ayúdame, Stackoverflow!
Tengo una aplicación de consola simple .NET 3.5 que lee algunos datos y envía correos electrónicos. Represento el formato de correo electrónico en una hoja de estilo XSLT para que podamos cambiar fácilmente la redacción del correo electrónico sin necesidad de volver a compilar la aplicación.
Estamos utilizando objetos de extensión para pasar datos al XSLT cuando aplicamos la transformación:
<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">
- De esta manera, podemos tener declaraciones como:
<p>
Dear <xsl:value-of select="EmailNotification:get_FullName()" />:
</p>
Lo anterior funciona bien. Paso el objeto a través de un código como este (se omite algún código irrelevante por brevedad):
// 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));
Entonces, todo el código anterior funciona . Sin embargo, quería hacerme un poco de fantasía (siempre mi caída) y pasar una colección para poder hacer algo como esto:
<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>
Cuando paso la colección en el objeto de extensión e intento de transformar, obtengo el siguiente error:
"Extension function parameters or return values which have Clr type ''String[]'' are not supported."
o Lista, o IEnumerable, o lo que sea que trate de pasar.
Entonces, mis preguntas son:
¿Cómo puedo pasar una colección a mi XSLT?
¿Qué debo poner para xsl: value-of select = "" dentro de xsl: for-each?
¿Es lo que estoy tratando de hacer imposible?
Editar: Después de ver las dos respuestas a continuación, tomé el código de Chris Hynes y lo modifiqué muy ligeramente para adaptarlo a mis necesidades. La solución es la siguiente:
// 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();
}
}
}
Y en mi XSLT ...
<xsl:for-each select="EmailNotification:get_StringsNodeSet()//String">
<ul>
<li>
<xsl:value-of select="." />
</li>
</ul>
</xsl:for-each>
Funcionó a la perfección!
La documentación dice:
El parámetro debe corresponder a un tipo de W3C. La siguiente tabla muestra los tipos W3C, ya sea XPath o XSLT, y la clase correspondiente .NET.
Y enumera los siguientes tipos:
- Cuerda
- Booleano
- Número
- Fragmento de árbol de resultado
- Conjunto de nodos
- Nodo
Entonces, la respuesta es que no puedes ... bueno al menos no directamente. Pero la mejor apuesta en tu caso es, en mi humilde opinión, el conjunto de nodos o nodos.