0

I am trying to transform xml using xslt having script but not able as code is throwing platform not supported exception with message Compiling JScript/CSharp scripts is not supported. Does dot net core support xml xslt transform with vb script? I am using 2.1 dot net core.

My code is :

XslCompiledTransform xslTransform = new XslCompiledTransform();
    
using (StringReader sr = new StringReader(xmlfile))
{
    using (XmlReader xr = XmlReader.Create(sr))
    {
        xslTransform.Load(xr, XsltSettings.TrustedXslt, myResolver);
    }
}
5
  • 2
    As far as I understand from github.com/dotnet/corefx/issues/19837, there is no support for embedded "script" calls with ms:script inside the XSLT but you should be able to use extension objects to call any .NET framework function as done in github.com/brandonh-msft/EmbeddedXsltTestFunction/blob/master/…. So you would need to move any VB code out of the XSLT and implement/wrap it as an extension object you pass with an XsltArgumentList to the Transform method. And it is JScript.NET or C# or VB.NET support you get, not VBScript. Commented May 30, 2019 at 12:54
  • Thanks Martin - I tried the way you told . I converted my VB Script functions in C# but I am getting an exception while transforming . Exception is - Cannot find a script or an extension object associated with namespace '{nameof(XSLTFunctions)}'. I have written this namespace in separate XSLT file. <xsl:stylesheet xmlns:xsl="w3.org/1999/XSL/Transform" xmlns:xs="w3.org/2001/XMLSchema" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0" xmlns:vb="{nameof(XSLTFunctions)}"> Commented May 31, 2019 at 7:34
  • 1
    You will need to edit your question and provide minimal but complete samples to allow us to reproduce the problem. From that snippet in a comment it is hard to tell what you tried and where it got wrong. Did you see the $ sign with the string literal containing the XSLT code? That means in the linked example the {nameof(XSLTFunctions)} is evaluated and the final XSLT is computed in the C# code. Commented May 31, 2019 at 7:51
  • 1
    If you write an external XSLT document use your own URI e.g. xmlns:mf="http://example.com/mf" in the XSLT and then mf:foo() to call a function in that namespace and xsltArgList.AddExtensionObject("http://example.com/mf", yourCSharpObjectOrClass). Commented May 31, 2019 at 7:52
  • Martin - After your last comment, I worked on setting URI of external XSLT. I set the C# script class name on run time by setting element attribute. it did what we wanted. really appreciate your help. I get some time I will post my own answer mentioning your approach. Big Thank You . +1 Commented Jun 3, 2019 at 7:12

1 Answer 1

1

Note: This answer is taken from the top-level comments on this question and this github repo (which is linked in the comments). I just pulled everything together in an answer to make it easier for future readers.

You can use extension objects to call your own C# methods from XSLT.

For example, define the methods you want to use:

public class XsltFunctions
{
    public static string ToLower(XPathNodeIterator iterator)
    {
        return iterator.OfType<XPathNavigator>().FirstOrDefault()?.Value.ToLower();
    }
}

Then register that class as an extensions object when running your XSLT. (Pay attention to the AddExtensionObject method.)

public string RunXslt(string inputXml)
{
    // xml transform pointing to custom code
    var xsltDocumentString = $@"<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"" xmlns:msxsl=""urn:schemas-microsoft-com:xslt"" xmlns:user=""{nameof(XsltFunctions)}""> 
    <xsl:template match=""MyElt"">
<MyElt>
    <OriginalValue>
        <xsl:copy-of select=""node()""/>
    </OriginalValue>
    <ToLowerValue>
        <xsl:value-of select=""user:ToLower(node())""/>
    </ToLowerValue>
</MyElt>
</xsl:template>
</xsl:stylesheet>";

    // Compile the style sheet.
    var xslt_settings = new XsltSettings();
    var xslt = new XslCompiledTransform();
    var styleSheetReader = new XmlTextReader(new StringReader(xsltDocumentString));
    xslt.Load(styleSheetReader, xslt_settings, new XmlUrlResolver());

    // Add capability to ref external functions
    var xsltArgList = new XsltArgumentList();
    xsltArgList.AddExtensionObject(nameof(XsltFunctions), new XsltFunctions());

    // Load the XML source file.
    XmlReader inputDataReader = new XmlTextReader(new StringReader(inputXml));

    // Create an XmlWriter.
    var settings = new XmlWriterSettings();
    settings.OmitXmlDeclaration = true;
    settings.Indent = true;

    var output = new StringBuilder();
    var writer = new XmlTextWriter(new StringWriter(output));

    // Execute the transformation.
    xslt.Transform(inputDataReader, xsltArgList, writer);

    // return the transformed XML response to the caller
    return output.ToString();
}

Tested in .NET Core 2.1 and .NET 5, using the following NUnit test.

[Test]
public void RunXsltWithExternalFunctions()
{
    // Arrange.
    var inputXml = @"<?xml version=""1.0"" encoding=""utf-8""?>
<MyXml>
    <MyElt>
        MyEltValue
    </MyElt>
</MyXml>";

    // Act.
    var outputXml = RunXslt(inputXml);

    // Assert.
    Assert.That(outputXml, Does.Contain("myeltvalue"));
}

Source

See also: XSLT Extension Objects

Sign up to request clarification or add additional context in comments.

1 Comment

This was the right solution for me. I had to change this part xmlns:user="{nameof(XsltFunctions)}" in the xslt template to xmlns:user=""{XsltFunctions}"" but I may have some other flaws in my code that caused my a problem here. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.