.NET Extension Objects с XSLT - как перебрать коллекцию? - PullRequest
10 голосов
/ 17 марта 2010

Помоги мне, 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: value-of select = "" внутри xsl: for-each?

То, что я пытаюсь сделать, невозможно?


Редактировать: После того, как я увидел два ответа ниже, я взял код Криса Хайнса и очень немного изменил его в соответствии со своими потребностями. Решение заключается в следующем:

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

9 голосов
/ 17 марта 2010

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;
}
2 голосов
/ 17 марта 2010

Документация гласит:

Параметр должен соответствовать типу W3C. В следующей таблице показаны типы W3C: XPath или XSLT и соответствующий класс .NET.

И перечисляет следующие типы:

  • Строка
  • Логический
  • Номер
  • Фрагмент дерева результатов
  • Набор узлов
  • Node

Итак, ответ не в том, что вы не можете ... ну, по крайней мере, не напрямую. Но лучшая ставка в вашем случае - это, ИМХО, узел или набор узлов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...