2010-03-16 44 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