Call C# function in XSLT by Saxon - c#

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

Related

I have an xml file that is styled with xslt to produce html email template. How can i get that xml as html email body in c#?

I have an xml file that is styled with xslt to produce html email template. I get values from users dynamically and replace xml elements text with the values received. How can i get that xml file and send as html email body in c#?
My Xml Looks Like This
<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/xsl" href="EmailTemplateStyleForHTML.xslt"?>
<EmailTemplate>
<subject>Information from xyz</subject>
<displayName>abcd</displayName>
<Message1>
Thanks you for registering to xyz.
</Message1>
<Copyright>Copyright xyz</Copyright>
</EmailTemplate>
I am using LINQ to set the values to the xml.
Note: I know how to get and set the values from xml but what i want is to grab the whole xml file in to the email body.
If you think there is a better approach for this i would love to hear that. I would really appreciate your help.
Edited after Reply:
The xsl transformation part :
TextReader tr1 = new StringReader(#"EMailTemplateHtml.xml");
var tr11 = new XmlTextReader(tr1);
var xPathDocument = new XPathDocument(tr11);
//read XSLT
TextReader tr2 = new StringReader(#"EmailTemplateStyleForHTML.xslt");
var tr22 = new XmlTextReader(tr2);
var xslt = new XslTransform();
xslt.Load(tr22);
var sb = new StringBuilder();
TextWriter tw = new StringWriter(sb);
xslt.Transform(xPathDocument, null, tw);
emailBody = sb.ToString();
I am doing the transformation as you said(#Roy Ashbrook) am i missing anything here?
I believe you will need to actually perform the XSL transform in memory, not reference it in the XML itself. It's possible you could store the XSL in a remote location and reference it that way, but I wouldn't
so:
inject your values into your xml string
transform your xml using your xsl
make that your html message body
Here is some code. Mostly borrowed from/inspired by:
How to transform XML as a string w/o using files in .NET? and Sending E-mail using C#.
void Main()
{
SendHtmlBody(GetHtmlBody());
}
void SendHtmlBody(string HtmlBody){
using(SmtpClient c = new SmtpClient())
{
//set smtp options here
using(MailMessage msg = new MailMessage("from#replace.me","to#replace.me"))
{
msg.Subject = "Testing Bulk mail application";
msg.Body = HtmlBody;
msg.IsBodyHtml = true;
//c.Send(msg);
}
}
}
string GetHtmlBody(){
string xmlInput = #"<?xml version=""1.0"" encoding=""utf-8"" ?>
<EmailTemplate>
<subject>Information from xyz</subject>
<displayName>abcd</displayName>
<Message1>
Thanks you for registering to xyz.
</Message1>
<Copyright>Copyright xyz</Copyright>
</EmailTemplate>";
string xslInput = #"<?xml version=""1.0"" encoding=""ISO-8859-1""?>
<xsl:stylesheet version=""1.0""
xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"">
<xsl:template match=""/"">
<html>
<body>
<h5><xsl:value-of select=""EmailTemplate/subject""/></h5>
<h5><xsl:value-of select=""EmailTemplate/displayName""/></h5>
</body>
</html>
</xsl:template>
</xsl:stylesheet>";
using (StringReader srt = new StringReader(xslInput)) // xslInput is a string that contains xsl
using (StringReader sri = new StringReader(xmlInput)) // xmlInput is a string that contains xml
{
using (XmlReader xrt = XmlReader.Create(srt))
using (XmlReader xri = XmlReader.Create(sri))
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xrt);
using (StringWriter sw = new StringWriter())
using (XmlWriter xwo = XmlWriter.Create(sw, xslt.OutputSettings)) // use OutputSettings of xsl, so it can be output as HTML
{
xslt.Transform(xri, xwo);
return sw.ToString();
}
}
}
}

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.

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?

Getting Variable values out of and XSLT file

I wanted to find out if there is a way of getting a parameter or variable value out of an XSL file. For example, if I have the following:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:variable name="username" select ="usertest"/>
<xsl:variable name="password" select ="pass"/>
<!-- ... -->
</xsl:stylesheet>
I would like to read the username and password values from the XSL and use them for authentication. I am using ASP.Net and C# to perform the actual transform on an XML file.
Could someone please share code with me that would allow me to read the XSL variables from ASP.NET/C#. Thanks in advance for the help.
This is easy. XSL files are XML themselves, so you can treat them as such.
XmlDocument xslDoc = new XmlDocument();
xslDoc.Load("myfile.xsl");
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xslDoc.NameTable);
nsMgr.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform");
XmlNode usrNode = xslDoc.SelectSingleNode("/xsl:stylesheet/xsl:variable[#name='username']", nsMgr);
XmlNode pwdNode = xslDoc.SelectSingleNode("/xsl:stylesheet/xsl:variable[#name='password']", nsMgr);
string usr = usrNode.Attributes["select"].Value;
string pwd = pwdNode.Attributes["select"].Value;
Your question is (edit: was) missing the actual code, but from the description it appears what you are looking for is XPath. XSL will transform one XML document into another XML document, you can then use XPath to query the resulting XML to get out the values that you want.
This Microsoft KB article has information about how to use XPath from C#:
http://support.microsoft.com/kb/308333
Thanks Everone. Here is what finally worked:
Client (asp with vbscript) Used for Testing Purposes:
<%
//Create Object
Set xmlhttp = CreateObject("Microsoft.XMLHTTP")
//Set up the object with the URL
'xmlhttp.open "POST" ,"http://localhost/ASP_Test/receiveXML.asp",False
//Create DOM Object
Set xmldom = CreateObject("Microsoft.XMLDOM")
xmldom.async = false
//Load xls to send over for transform
xmldom.load(Server.MapPath("/ASP_Test/masterdata/test.xsl"))
//Send transform file as DOM object
xmlhttp.send xmldom
%>
//////////////////////////////////////////////////////////////////////////
On the Server Side: (aspx with C#) Accepts xslt and process the transform:
//file path for data xml
String xmlFile = ("\\masterdata\\test.xml");
//file path for transformed xml
String xmlFile2 = ("\\masterdata\\out.xml");
XmlTextReader reader = new XmlTextReader(Request.InputStream);
Transform(xmlFile, reader, xmlFile2);
public static string Transform(string sXmlPath, XmlTextReader xslFileReader, string outFile)
{
try
{
//load the Xml doc
XPathDocument myXPathDoc = new XPathDocument(sXmlPath);
XslCompiledTransform myXslTrans = new XslCompiledTransform();
//load the Xsl
myXslTrans.Load(xslFileReader);
//create the output stream
XmlTextWriter myWriter = new XmlTextWriter
(outFile, null);
//do the actual transform of Xml
myXslTrans.Transform(myXPathDoc, null, myWriter);
myWriter.Close();
return "Done";
}
catch (Exception e)
{
return e.Message;
}
}

What's the property way to transform with XSL without HTML encoding my final output?

So, I am working with .NET. I have an XSL file, XslTransform object in C# that reads in the XSL file and transforms a piece of XML data (manufactured in-house) into HTML.
I notice that my final output has < and > automatically encoded into < and >. Is there any ways I can prevent that from happening? Sometimes I need to bold or italicize my text but it's been unintentionally sanitized.
Your xsl file should have:
an output of html
omit namespaces for all used in the xslt
i.e.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="xsl msxsl">
<xsl:output method="html" indent="no" omit-xml-declaration="yes"/>
<!-- lots -->
</xsl:stylesheet>
And you should ideally use the overloads that accept either a TextWriter or a Stream (not XmlWriter) - i.e. something like:
StringBuilder sb = new StringBuilder();
using (XmlReader reader = XmlReader.Create(source)
using (TextWriter writer = new StringWriter(sb))
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load("Foo.xslt"); // in reality, you'd want to cache this
xslt.Transform(reader, options.XsltOptions, writer);
}
string html = sb.ToString();
In the xslt, if you really want standalone < / > (i.e. you want it to be malformed for some reason), then you need to disable output escaping:
<xsl:text disable-output-escaping="yes">
Your malformed text here
</xsl:text>
However, in general it is correct to escape the characters.
I have used this in the past to transform XMl documents into HTML strings which is what you need.
public static string TransformXMLDocFromFileHTMLString(string orgXML, string transformFilePath)
{
System.Xml.XmlDocument orgDoc = new System.Xml.XmlDocument();
orgDoc.LoadXml(orgXML);
XmlNode transNode = orgDoc.SelectSingleNode("/");
System.Text.StringBuilder sb = new System.Text.StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.ConformanceLevel = ConformanceLevel.Auto;
XmlWriter writer = XmlWriter.Create(sb, settings);
System.Xml.Xsl.XslCompiledTransform trans = new System.Xml.Xsl.XslCompiledTransform();
trans.Load(transformFilePath);
trans.Transform(transNode, writer);
return sb.ToString();
}
(XslTransform is deprecated, according to MSDN. They recommend you switch to XslCompiledTransform.)
Can you post an example of the input/output?

Categories