2010-03-16 85 views
10

帮帮我,Stackoverflow!带有XSLT的.NET扩展对象 - 如何迭代集合?

我有一个简单的.NET 3.5控制台应用程序,它读取一些数据并发送电子邮件。我在XSLT样式表中表示电子邮件格式,以便我们可以轻松更改电子邮件的措辞,而无需重新编译应用程序。

我们使用扩展对象,当我们应用转换将数据传递给XSLT:

<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"> 

- 这样一来,我们就可以有这样的语句:

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

上述工程精细。我通过这样的代码传递对象(略去了一些不相关的代码):

// 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)); 

所以,上述所有代码的工作。不过,我想获得一点点花哨(一直是我的垮台),并通过收集,这样我就可以做这样的事情:

<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> 

当我通过集合中的扩展对象,并尝试变换,我出现以下错误:

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

或列表,或IEnumerable的,或不管我尝试通过

所以,我的问题是:

  1. 如何将集合传递给我的XSLT?

  2. 我在xsl:for-each里面为xsl:value-of select =“放了什么?

我试图做什么不可能?


编辑:我看见了下面两个答案后,我把克里斯·海因斯代码,并修改了它非常轻微,以满足我的需求。解决方法如下:

// 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(); 
     } 
    } 
} 

在我的XSLT ...

<xsl:for-each select="EmailNotification:get_StringsNodeSet()//String"> 
    <ul> 
     <li> 
      <xsl:value-of select="." /> 
     </li> 
    </ul> 
</xsl:for-each> 

完美地工作!

回答

9

XSLT for each需要一个节点集迭代 - 您不能直接从您的C#代码传回数组。您应该返回一个XPathNodeIterator。

事情是这样的:

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

谢谢!我现在要检查一下。 – Pandincus 2010-03-16 21:46:50

+0

@Chris Hynes:你的回答和示例代码正是我所需要的。我修改了你的示例代码,因为你不能设置XmlElement的Value属性(显然),我会在我的答案中暂时发布我的代码。 Obalix的解决方案也是正确的,但我只能接受一个答案,而示例代码真的超越 - 超越 - 使我的生活变得轻松。谢谢克里斯! – Pandincus 2010-03-16 22:08:35

+0

相应修改 - 我没有真正运行代码,只是写了* blush *。 – 2010-03-24 21:13:06

2

documentation状态:

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

,并列出以下几种类型:

  • 字符串
  • 布尔
  • 结果树片段
  • 节点集
  • 节点

所以,答案是不,你不能......嗯,至少没有直接。但在你的情况下最好的赌注是,恕我直言,节点或节点集。

+0

为什么我没有看文档对于XsltArgumentList.AddParam超出了我。 (今天晚了?)我要检查返回一个Node或NodeSet,看看它是否有效。谢谢! – Pandincus 2010-03-16 21:47:44