【问题标题】:.NET Extension Objects with XSLT -- how to iterate over a collection?带有 XSLT 的 .NET 扩展对象——如何遍历集合?
【发布时间】:2011-01-28 08:06:28
【问题描述】:

帮助我,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="" 放什么?

我想做的事不可能吗?


编辑:在看到下面的两个答案后,我采用了 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>

完美运行!

【问题讨论】:

    标签: c# .net email xslt


    【解决方案1】:

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

    【讨论】:

    • @Chris Hynes:您的答案和示例代码正是我所需要的。我稍微修改了您的示例代码,因为您无法设置 XmlElement 的 Value 属性(显然),我将立即在我的答案中发布我的代码。 Obalix 的解决方案也是正确的,但我只能接受一个答案,并且示例代码真的超凡脱俗——让我的生活变得轻松。谢谢克里斯!
    • 相应修改——我并没有实际运行代码,只是写出来* blush *。
    • 也可以返回XPathNavigatorXPathNavigator[],比返回XPathNodeIterator方便,而且不需要调用Select(".")
    【解决方案2】:

    documentation 声明:

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

    并列出以下类型:

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

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

    【讨论】:

    • 为什么我没有查看 XsltArgumentList.AddParam 的文档,这超出了我的理解。 (今天太晚了?)我要检查返回一个节点或节点集,看看它是否有效。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-17
    相关资源
    最近更新 更多