Embedded C# in msxsl:script
Set enableScripts to true. Script blocks are compiled with Roslyn when the map is first used, then cached per worker.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:fmt="urn:samples:format"
exclude-result-prefixes="msxsl fmt">
<msxsl:script language="C#" implements-prefix="fmt">
<![CDATA[
private static readonly System.Globalization.CultureInfo Invariant = System.Globalization.CultureInfo.InvariantCulture;
public string Money(double amount, string currency)
{
return amount.ToString("#,##0.00", Invariant) + " " + currency;
}
public string PostalCode(string value)
{
var code = Regex.Replace(value ?? "", "[^A-Za-z0-9]", "").ToUpperInvariant();
return code.Length == 6 ? code.Substring(0, 3) + " " + code.Substring(3) : code;
}
]]>
</msxsl:script>
<xsl:template match="/Order">
<Total><xsl:value-of select="fmt:Money(sum(Lines/Line/Amount), 'CAD')"/></Total>
<PostalCode><xsl:value-of select="fmt:PostalCode(string(ShipTo/PostalCode))"/></PostalCode>
</xsl:template>
</xsl:stylesheet>What is supported
- Public instance methods with
string,boolanddoubleparameters and return values (XPath string, boolean, number). - Private helpers, instance fields, and
static readonlyorconstfields. A fresh instance per transformation, so state never leaks between runs. - Namespaces:
System,System.TextandSystem.Text.RegularExpressionsare in scope; write other framework types with their full names (System.Globalization.CultureInfo). - Several blocks. Binding is by namespace URI: blocks with the same URI form one class, under any prefix; scripts in imported modules work too.
- C# only (C# 12 syntax). VB and JScript blocks,
msxsl:assembly, and out-of-subset features are rejected withUnsupportedScriptFeature, naming the line and rule.
Errors point at the map
Compile errors carry the original map line: ScriptCompilationFailed: … errors/script-syntax-error.xslt(9,30): CS1002 ; expected. Exceptions thrown by a script give ScriptExecutionFailed with the method name and exception type, never the data.
Scripts run in a worker process. A loop that never returns is stopped at the action's timeoutSeconds with TransformationTimeout; the worker is killed and replaced, and the next run works normally.
Operators can turn scripts off for the whole app with XsltCompose__AllowScripts=false (ScriptsDisabled).