简体   繁体   English

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

[英].NET Extension Objects with XSLT — how to iterate over a collection?

Help me, Stackoverflow! 帮帮我,Stackoverflow!

I have a simple .NET 3.5 console app that reads some data and sends emails. 我有一个简单的.NET 3.5控制台应用程序,它可以读取一些数据并发送电子邮件。 I'm representing the email format in an XSLT stylesheet so that we can easily change the wording of the email without needing to recompile the app. 我在XSLT样式表中表示电子邮件格式,以便我们可以轻松更改电子邮件的措辞,而无需重新编译应用程序。

We're using Extension Objects to pass data to the XSLT when we apply the transformation: 我们在应用转换时使用扩展对象将数据传递给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">

-- this way, we can have statements like: - 这样,我们可以有这样的陈述:

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

The above works fine. 以上工作正常。 I pass the object via code like this (some irrelevant code omitted for brevity): 我通过这样的代码传递对象(为简洁起见省略了一些不相关的代码):

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

So, all of the above code works . 所以, 以上所有代码都有效 However, I wanted to get a little fancy (always my downfall) and pass a collection, so that I could do something like this: 但是,我想得到一点点幻想(总是我的垮台)并传递一个集合,这样我就能做到这样的事情:

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

When I pass the collection in the extension object and attempt to transform, I get the following error: 当我在扩展对象中传递集合并尝试转换时,我收到以下错误:

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

or List, or IEnumerable, or whatever I try to pass in. 或List,或IEnumerable,或我尝试传入的任何内容。

So, my questions are: 所以,我的问题是:

  1. How can I pass in a collection to my XSLT? 如何将集合传递给我的XSLT?

  2. What do I put for the xsl:value-of select="" inside the xsl:for-each ? 我在xsl:for-each中为xsl:value-of select =“”放了什么?

Is what I am trying to do impossible? 我想做什么不可能?


Edit: After I saw the two answers below, I took Chris Hynes' code and modified it very slightly to suit my needs. 编辑:在我看到下面的两个答案之后,我拿了Chris Hynes的代码并稍微修改它以满足我的需要。 Solution is as follows: 解决方案如下:

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

And in my XSLT ... 在我的XSLT中......

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

Worked perfectly! 工作得很完美!

The XSLT for-each expects a node set to iterate over -- you can't directly pass an array back from your C# code. XSLT for-each期望一个节点集迭代 - 你不能直接从C#代码传回一个数组。 You should return an XPathNodeIterator. 您应该返回XPathNodeIterator。

Something like this: 像这样的东西:

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

The documentation states: 文件说明:

The parameter should correspond to a W3C type. 该参数应对应于W3C类型。 The following table shows the W3C types, either XPath or XSLT, and the corresponding.NET class. 下表显示了W3C类型(XPath或XSLT)以及相应的.NET类。

And lists the following types: 并列出以下类型:

  • String
  • Boolean 布尔
  • Number
  • Result Tree Fragment 结果树片段
  • Node Set 节点集
  • Node 节点

So, the answer is not you can't ... well at least not directly. 所以,答案不是你不能......至少不是直接的。 But the best bet in your case is, IMHO, the Node or Node Set. 但在你的情况下,最好的选择是,恕我直言,节点或节点集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM