使用XSLT的.NET扩展对象 - 如何迭代集合?

时间:2010-03-16 21:37:43

标签: c# .net email xslt

帮帮我,Stackoverflow!

我有一个简单的.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."

或List,或IEnumerable,或我尝试传入的任何内容。

所以,我的问题是:

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

  2. 我在xsl:for-each中为xsl:value-of select =“”添加了什么?

  3. 我想做的不可能吗?


    编辑:在我看到下面的两个答案之后,我采用了Chris Hynes的代码并对其进行了微调,以满足我的需求。解决方案如下:

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

    工作得很完美!

2 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:2)

documentation州:

  

参数应对应于W3C类型。下表显示了W3C类型,XPath或XSLT,以及相应的.NET类。

并列出以下类型:

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

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