XslTransform to XslCompiledTransform - c#

Currently I have this code which works fine but I want to migrate to XslCompiledTransform. When this code was written the evidence was required or it would not work. Does anybody know if this is still required in the XslCompiledTransform.
XslTransform transformer = new XslTransform();
transformer.Load( navigator, new XmlUrlResolver(), this.GetType().Assembly.Evidence);
Here is my suggested code to change to.
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load( navigator,new XsltSettings(), new XmlUrlResolver() );

If you use new XsltSettings() then you are using default settings with both script and the document function being disabled. That would be equivalent to using
XslTransform transformer = new XslTransform();
transformer.Load( navigator, new XmlUrlResolver(), null);

Related

Blazor - 'msxsl:script' element is not supported on this framework because it does not support run-time code generation

I have a problem with using XslCompiledTransform in Blazor Webassembly.
blazor.webassembly.js:1 crit:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: 'msxsl:script' element is not
supported on this framework because it does not support run-time code
generation
public async Task<string> TransformSomething(string xml, string kluczPakietu, string kodPakietu)
{
var xslFile = await _httpClient.GetByteArrayAsync("transform.xsl");
//change bytearray to string - valid is working here.
string transformataHTML = System.Text.Encoding.Default.GetString(xslFile);
XDocument oldDocument = XDocument.Parse(xml);
var newDocument = new XDocument();
using (var stringReader = new StringReader(transformataHTML))
{
using (XmlReader xsltReader = XmlReader.Create(stringReader))
{
XsltArgumentList argsList = new XsltArgumentList();
argsList.AddParam("SVG", "", "enabled");
argsList.AddParam("klucz", "", kluczPakietu);
argsList.AddParam("kod", "", kodPakietu);
XsltSettings xsltSettings = new XsltSettings();
xsltSettings.EnableDocumentFunction = true;
xsltSettings.EnableScript = true;
var transformer = new XslCompiledTransform();
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xsltReader);
//here is exception
transformer.Load(xsltReader, xsltSettings, new XmlUrlResolver());
//transformer.Load(xsltReader);
using (XmlReader oldDocumentReader = oldDocument.CreateReader())
{
using (XmlWriter newDocumentWriter = newDocument.CreateWriter())
{
transformer.Transform(oldDocumentReader, argsList, newDocumentWriter);
}
}
}
}
return newDocument.ToString();
}
Is it possible to do it in Blazor Webassembly? In Blazor Server-side the script works.
XslCompiledTransform would try to generate new .NET code at run-time and would expect a JIT to compile it to native code for the underlying machine. Since WebAssembly does not support this (just like other platforms that require AOT like iOS), you cannot use it.
Use the XslTransform class instead of XslCompiledTransform to work with XSLT on these platforms.
Update: Also note that scripts inside XSLT always need run-time code generation, so even if XslCompiledTransform would fall back to non-compiled transform, scripts are only implemented for run-time code generation at the moment:
The XslCompiledTransform class supports embedded scripts using the
msxsl:script element. When the style sheet is loaded, any defined
functions are compiled to Microsoft intermediate language (MSIL) by
the Code Document Object Model (CodeDOM) and are executed during run
time. The assembly generated from the embedded script block is
separate than the assembly generated for the style sheet.
Source

Call C# function in XSLT by Saxon

I have a XSLT file in C# project like this:
<msxsl:script language="C#" implements-prefix="user">
<![CDATA[
public string Test()
{
return "test1";
}
]]>
</msxsl:script>
...
<xsl:value-of select="user:Test()"/>
I transformed my XML file by this XSLT like this:
//Enable execute C# function in xslt
var Xsltsettings = new XsltSettings();
Xsltsettings.EnableScript = true;
XslCompiledTransform xsl = new XslCompiledTransform();
xsl.Load(XslFile, Xsltsettings, new XmlUrlResolver());
// get transformed results
StringWriter sw = new StringWriter();
XsltArgumentList xslarg = new XsltArgumentList();
xsl.Transform(xdoc, xslarg, sw);
sw.Close();
I try to use from XSLT 2.0 by saxon9he-api like this:
Processor processor = new Processor();
// Load the source document.
string sourceUri = #"D:\testXML.xml";
XdmNode input = processor.NewDocumentBuilder().Build(new Uri(sourceUri));
// Create a transformer for the stylesheet.
string xsltUri = #"D:\testXSLT.xslt";
XsltTransformer transformer = processor.NewXsltCompiler().Compile(new Uri(xsltUri)).Load();
// Set the root node of the source document to be the initial context node.
transformer.InitialContextNode = input;
Serializer serializer = new Serializer();
StringBuilder sb = new StringBuilder();
TextWriter writer = new StringWriter(sb);
serializer.SetOutputWriter(writer);
transformer.Run(serializer); //Error line
But this code has error below:
Cannot find a matching 0-argument function named {urn:my-scripts}Test()
I read many post but I didn't find solution for solve this problem.
It would be very helpful if someone could explain solution for this issue.
Saxon does not support the proprietary Microsoft extensions. XSLT extensions are generally not portable between processors of different types.
You will have to re-write your existing, C#-based extension function in Java and(see comment below) switch to Saxon's own proprietary extension mechanism.
Read
http://www.saxonica.com/html/documentation/extensibility/functions/
http://www.saxonica.com/html/documentation/extensions/functions/saxon-extension-functions.html

Apply XSLT on an XmlDocument and get the updated XmlDocument

I've to make an upgrade mechanism which will update an XML documents(To another xml document).
The signature of the method that I've to respect is :
public XmlDocument Update(XmlDocument sourceDocument){...}
What would be the most efficient way to apply an XSLT file on this?
I was expecting to be able to use the XslTransform class, but it only accept stream and XmlWriter as parameter for the output.
So I know that I could do something like:
public XmlDocument Update(XmlDocument sourceDocument){
XslTransform myXslTransform = new XslTransform();
myXslTransform.Load("myXsl.xsl");
MemoryStream ms = new MemoryStream();
myXslTransform.Transform(sourceDocument, null, ms);
XmlDocument output = new XmlDocument();
output.Load(ms);
return output;
}
But I find this not very efficient(knowing that my XSLT will be to rename some nodes, add a node in-between, add a child). Is there a way to do better?
My "only" constraints are: Input/Output: XmlDocument, External XSLT to load.
If you want to use a System.Xml.XmlDocument with the current XSLT 1.0 implementation (XslCompiledTransform) that Microsoft offers then you can use
XmlDocument resultDocument = new XmlDocument();
using (XmlWriter xw = resultDocument.CreateNavigator().AppendChild()) {
XslCompiledTransform proc = new XslCompiledTransform();
proc.Load("myXsl.xsl");
proc.Transform(sourceDocument, null, xw);
xw.Close();
}
return resultDocument;

Output Param from XSLT

I have been familiar with passing Input Param to XSLT CompiledTransformation class, so that parser takes care of XSL file making use of Param in processing instruction provided in XSL file.
Is there a way where we can get output param (say a value of node or something else) from XSLT to host language like C#??
XslCompiledTransform xslTransform = new XslCompiledTransform();
string strXmlOutput = string.Empty;
StringWriter swXmlOutput = null;
MemoryStream objMemoryStream = null;
XPathDocument xpathXmlOrig = new XPathDocument(string_xmlInput);
swXmlOutput = new StringWriter();
objMemoryStream = new MemoryStream();
xslArg.AddParam("TESTING", "", SomeVar);
XsltSettings xslsettings = new XsltSettings(false, true);
xslTransform.Load(string_xslInput, xslsettings, new XmlUrlResolver());
xslTransform.Transform(xpathXmlOrig, xslArg, objMemoryStream);
This code indeed outputs transformed XML, but my question is can we take just one value as output param from XSL Tranformation (XSLT file)??
Something like this:
xslArg.OutputParam("testing"); //Something like this?
........
........
xslTransform.Transform(xpathXmlOrig, xslArg, objMemoryStream);
string outputparam = xslArg.GetParam("testing"); //ideal way of getting param after traformation!
Does XSLT provides scope for something like this?
In C#, your best bet is to put <xsl:message> instructions in your XSLT code, and hook into the XsltMessageEncountered event on the XsltArgumentList class.
You can test it's giving you the correct output without hooking the event, by watching the output of the app- in the absence of an event handler, messages are piped to standard output.

XslTransform class is deprecated after .NET conversion

I had XslTransform in an old program, and after converting the code the the .NET F 3.5, the compiler said that XslTransform is deprecated and replaced by XslCompiledTransform.
This is the old code :
XslTransform xslt = new XslTransform();
xslt.Load(xslTemplate);
xslt.Transform(xPathNav, null, fileStream, null);
I've changed the code to look like this :
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xslTemplate);
xslt.Transform(xPathNav, fileStream);
And now I get :
cannot convert from
'System.IO.FileStream' to
'System.Xml.XmlWriter'
I tried to correct that by adding doing this :
XPathDocument doc = new XPathDocument(fileStream);
XmlWriter writer = XmlWriter.Create(Console.Out, xslt.OutputSettings);
xslt.Transform(doc, writer);
I don't get errors anymore, but I the code is not doing XML transformation.
Any ideas ?
Thanks.
I think
XslTransform xslt = new XslTransform();
xslt.Load(xslTemplate);
xslt.Transform(xPathNav, null, fileStream, null);
can be written as follows with XslCompiledTransform
XslTransform xslt = new XslCompiledTransform();
xslt.Load(xslTemplate);
xslt.Transform(xPathNav, null, fileStream);
MSDN actually has a full article on Migrating From XslTransform to XslCompiledTransform
In the first couple of code snippets, you seem to be using fileStream for output and xPathNav for input.
But in the last snippet, you're using fileStream (via doc) for input.
Did you really change fileStream to be your input document, or is this a mistake?

Categories