2010-03-16 12 views
10

¡Ayúdame, Stackoverflow!Objetos de extensión .NET con XSLT: ¿cómo iterar sobre una colección?

Tengo una aplicación de consola .NET 3.5 simple 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 los datos a la 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 frases como:

<p> 
    Dear <xsl:value-of select="EmailNotification:get_FullName()" />: 
</p> 

Los trabajos anteriores multa. Paso el objeto a través de un código como este (algo de código irrelevante omitido por razones de 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)); 

Así, todo el código anterior funciona. Sin embargo, quería conseguir un poco de fantasía (siempre mi caída) y pasar una colección, por lo que podría 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 y tratar de transformar, me el siguiente error:.

"Extension function parameters or return values which have Clr type 'String[]' are not supported." 

o Lista o IEnumerable, o lo que intento transmitir en

por lo tanto, mis preguntas son:

  1. ¿Cómo puedo pasar una colección a mi XSLT?

  2. ¿Qué debo poner para el xsl: value-of select = "" dentro del xsl: for-each?

¿Es lo que estoy tratando de hacer imposible?


Editar: Después de ver las dos respuestas a continuación, Tomé código Chris Hynes y lo modificó ligeramente para adaptarse a mis necesidades. 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!

Respuesta

9

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; 
} 
+0

Gracias! Voy a verificar eso ahora mismo. – Pandincus

+0

@Chris Hynes: Su respuesta y código de muestra eran exactamente lo que necesitaba. Modifiqué un poco tu código de muestra porque no puedes establecer la propiedad Value de un XmlElement (aparentemente), y publicaré mi código en mi respuesta momentáneamente. La solución de Obalix también era correcta, pero solo puedo aceptar una respuesta y el código de muestra estaba realmente por encima y más allá, hizo mi vida más fácil. Gracias Chris! – Pandincus

+0

Modificado en consecuencia - No ejecuté el código, simplemente lo escribí * blush *. –

2

Los documentation estados:

The parameter should correspond to a W3C type. The following table shows the W3C types, either XPath or XSLT, and the corresponding.NET class.

y las listas de los siguientes tipos:

  • Cuerda
  • booleana
  • Número
  • Resultado árbol Fragmento
  • Conjunto de nodos
  • Nodo

Por lo tanto, la respuesta no es no se puede ... bueno, al menos no directamente. Pero la mejor apuesta en tu caso es, en mi humilde opinión, el conjunto de nodos o nodos.

+0

¿Por qué no miré la documentación? para XsltArgumentList.AddParam está más allá de mí. (¿Demasiado tarde en el día?) Voy a verificar devolver un Node o NodeSet y ver si eso funciona. ¡Gracias! – Pandincus

Cuestiones relacionadas