5

I am received the following error while trying to implement a C# extension function in XSLT.

Extension function parameters or return values which have CLR type 'Char[]' are not supported.**

code:

<xsl:variable name="stringList">
  <xsl:value-of select="extension:GetList('AAA BBB CCC', ' ')"/>
</xsl:variable> 

<msxsl:script language="C#" implements-prefix="extension">
<![CDATA[

public string[] GetList(string str, char[] delimiter)
{
   ...
   ...
   return str.Split(delimiter, StringSplitOptions.None);
}

]]>
</msxsl:script>

Can someone explain this error message and how to get past it?

EDIT: I need a solution that still lets me implement the split function and make use of the array returned.

Thanks!

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
developer
  • 7,252
  • 14
  • 49
  • 57
  • @iHeartGreek: You ask for someone to explain this error. Now, if you want a tokenize function, you must ask another question. This can be done in pure XSLT, no need for extension nor script. –  Jun 15 '10 at 17:58
  • @Alejandro: No.. that was my original intent. Have the error explained and how to get past it. My edit made it more clear that "how to get past it" meant that I need to be able to still do what I want. Sorry for the confusion, and thank you for your contributions. I would have selected the other answer either way due to his/her use of a easy to read table explanation. Thanks though! :D – developer Jun 15 '10 at 18:27
  • @iHeartGreek: Yes. I'm not looking for you to endorse my answer. I'm saying that what you want now (wich differ from your first questions) it can be done with pure XSLT. In this way, your question may help others not to think that to split a string is necessary to use an extension. –  Jun 15 '10 at 19:19
  • @Alejandro: Oh ok I see what you mean. Yes it can be done purely in xslt, and I have done so already, but now I wanted to use an extension function because my code got really complex and difficult to read using the recursion, and it seemed cleaner to switch to the C# in my scenario. For simple split, yes it would be better in xslt. Thanks for the suggestion :D – developer Jun 15 '10 at 19:31
  • @iHeartGreek: You wrote: "I wanted to use an extension function because my code got really complex and difficult to read using the recursion". That way of thinking is what I want to avoid. There are simples ones: http://stackoverflow.com/questions/136500/does-xslt-have-a-split-function. There are complex ones: http://stackoverflow.com/questions/1018974/tokenizing-and-sorting-with-xslt-1-0. Also note when you call repeatedly an extension function in MSXSL, the system requires loading the script engine multiple times. –  Jun 15 '10 at 22:13
  • @Alejandro: That is a good point about the loading the script engine :) but in order to achieve what I need to do, it requires a lot of extra code within the recursive xsl, which makes it way too messy and unreadable.. and it will only continue to grow with the rest of the project. In this scenario I will sacrifice small performance for readability and maintainability. Thanks though for your concern and suggestions :) – developer Jun 16 '10 at 14:26

2 Answers2

10

XSLT extension methods must return a type that is supported within XSL transformations. The following table shows the W3C XPath types and their corresponging .NET type:

W3C XPath Type        | Equivalent .NET Class (Type)
------------------------------------------------------
String                | System.String
Boolean               | System.Boolean
Number                | System.Double
Result Tree Fragment  | System.Xml.XPath.XPathNavigator
Node Set              | System.Xml.XPath.XPathNodeIterator

The table is taken from the section Mapping Types between XSLT and .NET in this MSDN Magazine article.

Instead of returning a string[] array you would have to return an XPathNodeIterator like it is done in the following example:

<msxsl:script implements-prefix="extension" language="C#">
<![CDATA[

public XPathNodeIterator GetList(string str, string delimiter)
{
    string[] items = str.Split(delimiter.ToCharArray(), StringSplitOptions.None);
    XmlDocument doc = new XmlDocument();
    doc.AppendChild(doc.CreateElement("root"));
    using (XmlWriter writer = doc.DocumentElement.CreateNavigator().AppendChild())
    {
        foreach (string item in items)
        {
            writer.WriteElementString("item", item);
        }
    }
    return doc.DocumentElement.CreateNavigator().Select("item");
}
]]>
</msxsl:script>

In your XSL transform you can then iterate over the elements in the returned node set using xsl:for-each:

<xsl:template match="/">
    <root>
        <xsl:for-each select="extension:GetList('one,two,three', ',')">
            <value>
                <xsl:value-of select="."/>
            </value>
        </xsl:for-each>
    </root>
</xsl:template>
Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
  • So I absolutely cannot have any sort of list? I need to use this split function, which gives me a list. How would you suggest getting around this? (this was the other part of my question.. how to get past the error.. but I will update my question to reflect this more clearly..) – developer Jun 15 '10 at 16:22
  • @iHeartGreek: I already updated with an example. Would that solve your problem? – Dirk Vollmar Jun 15 '10 at 16:23
  • thanks! I believe this will work. And I then get each value using for-each in the xsl right? – developer Jun 15 '10 at 16:30
  • Solved my problem. Thank you. – Samy Boulos Oct 28 '19 at 23:45
0

From http://msdn.microsoft.com/en-us/library/533texsx(VS.71).aspx

The supplied arguments and return values defined by the script functions must be one of the W3C XPath or XSLT types. The following table shows the corresponding W3C types, the equivalent .NET classes (Type), and whether the W3C Type is an XPath Type or XSLT Type.