Output Param from XSLT - c#

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.

Related

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

Weird character encoded characters (’) appearing from a feed

I've got a question regarding an XML feed and XSL transformation I'm doing. In a few parts of the outputted feed on an HTML page, I get weird characters (such as ’) appearing on the page.
On another site (that I don't own) that's using the same feed, it isn't getting these characters.
Here's the code I'm using to grab and return the transformed content:
string xmlUrl = "http://feedurl.com/feed.xml";
string xmlData = new System.Net.WebClient().DownloadString(xmlUrl);
string xslUrl = "http://feedurl.com/transform.xsl";
XsltArgumentList xslArgs = new XsltArgumentList();
xslArgs.AddParam("type", "", "specifictype");
string resultText = Utils.XslTransform(xmlData, xslUrl, xslArgs);
return resultText;
And my Utils.XslTransform function looks like this:
static public string XslTransform(string data, string xslurl)
{
TextReader textReader = new StringReader(data);
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Ignore;
XmlReader xmlReader = XmlReader.Create(textReader, settings);
XmlReader xslReader = new XmlTextReader(Uri.UnescapeDataString(xslurl));
XslCompiledTransform myXslT = new XslCompiledTransform();
myXslT.Load(xslReader);
StringBuilder sb = new StringBuilder();
using (TextWriter tw = new StringWriter(sb))
{
myXslT.Transform(xmlReader, new XsltArgumentList(), tw);
}
string transformedData = sb.ToString();
return transformedData;
}
I'm not extremely knowledgeable with character encoding issues and I've been trying to nip this in the bud for a bit of time and could use any suggestions possible. I'm not sure if there's something I need to change with how the WebClient downloads the file or something going weird in the XslTransform.
Thanks!
Give HtmlEncode a try. So in this case you would reference System.Web and then make this change (just call the HtmlEncode function on the last line):
string xmlUrl = "http://feedurl.com/feed.xml";
string xmlData = new System.Net.WebClient().DownloadString(xmlUrl);
string xslUrl = "http://feedurl.com/transform.xsl";
XsltArgumentList xslArgs = new XsltArgumentList();
xslArgs.AddParam("type", "", "specifictype");
string resultText = Utils.XslTransform(xmlData, xslUrl, xslArgs);
return HttpUtility.HtmlEncode(resultText);
The character â is a marker of multibyte sequence (’) of UTF-8-encoded text when it's represented as ASCII. So, I guess, you generate an HTML file in UTF-8, while browser interprets it otherwise. I see 2 ways to fix it:
The simplest solution would be to update the XSLT to include the HTML meta tag that will hint the correct encoding to browser: <meta charset="UTF-8">.
If your transform already defines a different encoding in meta tag and you'd like to keep it, this encoding needs to be specified in the function that saves XML as file. I assume this function took ASCII by default in your example. If your XSLT was configured to generate XML files directly to disk, you could adjust it with XSLT instruction <xsl:output encoding="ASCII"/>.
To use WebClient.DownloadString you have to know what the encoding the server is going use and tell the WebClient in advance. It's a bit of a Catch-22.
But, there is no need to do that. Use WebClient.DownloadData or WebClient.OpenReader and let an XML library figure out which encoding to use.
using (var web = new WebClient())
using (var stream = web.OpenRead("http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml"))
using (var reader = XmlReader.Create(stream, new XmlReaderSettings { DtdProcessing = DtdProcessing.Parse }))
{
reader.MoveToContent();
//… use reader as you will, including var doc = XDocument.ReadFrom(reader);
}

Saxon .Net transformation

Maybe this is a dumb question but I'm a totally newbie when it comes to XSL.
I'm using this command line to perform a transformation which works great:
transform.exe -s: source.xml -xsl:rules.xsl -o: output.xml -xi:on
I'm trying to achieve the same result from c# but the output file is empty. What is the equivalent of the "-xi" parameter?
Thanks.
Uri xslUri = new Uri(#"rules.xsl");
Uri inputUri = new Uri(#"source.xml");
Uri outputUri = new Uri(#"toc.hhc");
// Compile stylesheet
try
{
Processor processor = new Processor();
XdmNode input = processor.NewDocumentBuilder().Build(inputUri);
XsltCompiler compiler = processor.NewXsltCompiler();
XsltExecutable exec = compiler.Compile(xslUri);
XsltTransformer transformer = exec.Load();
transformer.InitialContextNode = input;
// Create a serializer
Serializer serializer = new Serializer();
FileStream fs = new FileStream(outputUri.AbsolutePath, FileMode.Create, FileAccess.Write);
serializer.SetOutputStream( fs );
// Transform the source XML to System.out.
transformer.Run( serializer );
}
catch( Exception e )
{
Console.WriteLine( e.Message );
}
I tried to set proc.Implementation.setXIncludeAware(true); but it did not work for me with Saxon 9.6.0.7. Therefore I posted my result at https://saxonica.plan.io/boards/3/topics/6206 and Saxonica created the bug report https://saxonica.plan.io/issues/2488 which was fixed later on. So it seems you have to wait until the fix is included in a new release to be able to use XInclude in a .NET application.
I would need to test it to be 100% sure that it works, but I think you should be able to do
processor.setProperty("http://saxon.sf.net/feature/xinclude-aware", "true")

Apply XSLT on in-memory XML and returning in-memory XML

I am looking for a static function in the .NET framework which takes an XML snippet and an XSLT file, applies the transformation in memory, and returns the transformed XML.
I would like to do this:
string rawXml = invoiceTemplateDoc.MainDocumentPart.Document.InnerXml;
rawXml = DoXsltTransformation(rawXml, #"c:\prepare-invoice.xslt"));
// ... do more manipulations on the rawXml
Alternatively, instead of taking and returning strings, it could be taking and returning XmlNodes.
Is there such a function?
You can use the StringReader and StringWriter classes :
string input = "<?xml version=\"1.0\"?> ...";
string output;
using (StringReader sReader = new StringReader(input))
using (XmlReader xReader = XmlReader.Create(sReader))
using (StringWriter sWriter = new StringWriter())
using (XmlWriter xWriter = XmlWriter.Create(sWriter))
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load("transform.xsl");
xslt.Transform(xReader, xWriter);
output = sWriter.ToString();
}
A little know feature is that you can in fact transform data directly into a XmlDocument DOM or into a LINQ-to-XML XElement or XDocument (via the CreateWriter() method) without having to pass through a text form by getting an XmlWriter instance to feed them with data.
Assuming that your XML input is IXPathNavigable and that you have loaded a XslCompiledTransform instance, you can do the following:
XmlDocument target = new XmlDocument(input.CreateNavigator().NameTable);
using (XmlWriter writer = target.CreateNavigator().AppendChild()) {
transform.Transform(input, writer);
}
You then have the transformed document in the taget document. Note that there are other overloads on the transform to allow you to pass XSLT arguments and extensions into the stylesheet.
If you want you can write your own static helper or extension method to perform the transform as you need it. However, it may be a good idea to cache the transform since loading and compiling it is not free.
Have you noticed that there is the XsltCompiledTransform class?

how to monitor the program code execution? (file creation and modification by code lines etc)

My program is about triggering XSL transformation,
Its fact that this code for carrying out the transformation, creates some dll and tmp files and deletes them pretty soon after the transformation is completed.
It is almost untraceable for me to monitor the creation and deletion of files manually, so I want to include some chunk of codelines to display "which codeline has created/modified which tmp and dll files" in console window.
This is the relevant part of the code:
string strXmlQueryTransformPath = #"input.xsl";
string strXmlOutput = string.Empty;
StringReader srXmlInput = null;
StringWriter swXmlOutput = null;
XslCompiledTransform xslTransform = null;
XPathDocument xpathXmlOrig = null;
XsltSettings xslSettings = null;
MemoryStream objMemoryStream = null;
objMemoryStream = new MemoryStream();
xslTransform = new XslCompiledTransform(false);
xpathXmlOrig = new XPathDocument("input.xml");
xslSettings = new XsltSettings();
xslSettings.EnableScript = true;
xslTransform.Load(strXmlQueryTransformPath, xslSettings, new XmlUrlResolver());
xslTransform.Transform(xpathXmlOrig, null, objMemoryStream);
objMemoryStream.Position = 0;
StreamReader objStreamReader = new StreamReader(objMemoryStream);
strXmlOutput = objStreamReader.ReadToEnd();
// make use of Data in string "strXmlOutput"
google and msdn search couldn't help me much..
The temporary DLLs will be created as part of the XSLCompiledTransform object: the XSLT document is compiled at run-time into MSIL and that generated assembly is used to perform the actual transformation. If you really want to work out exactly when the DLL appears/disappears, you could just step through the code, line by line, in a debugger and watch the Temp directory.
Why do you care about the temporary files, though? They're just an implementation detail of the XSL transform code that shouldn't matter to your code.
http://msdn.microsoft.com/en-us/library/system.xml.xsl.xslcompiledtransform.temporaryfiles.aspx
for this particular example.

Categories