Illegal characters in path exception when Transforming XML - c#

I am loading XML from a file, and then I want to transform it with XSLT to HTML. For that purpose I use the overload of Transform with 2 strings as parameters and therefore I make the XML into string. (The XSL is working - checked separately). But when I try to run it - I get exception at the result parameter of the .Transform() method.
XmlDocument xml = new XmlDocument();
XslCompiledTransform xsltTrans = new XslCompiledTransform();
string htmlResult = "test";
string xmlContents;
private string getXMLAsString(XmlDocument myxml)
{
StringWriter sw = new StringWriter();
XmlTextWriter tx = new XmlTextWriter(sw);
myxml.WriteTo(tx);
string str = sw.ToString();
return str;
}
public String getHTMLresult()
{
xml.Load(#"L:\ProjectGroup\GK\XML documents\Parent-Child.xml");
xmlContents = getXMLAsString(xml);
xsltTrans.Load(#"L:\ProjectGroup\GK\XML documents\blah.xsl");
xsltTrans.Transform(xmlContents, htmlResult);
return htmlResult;
}
Is it because htmlResult already has a value? But if I leave it blank, or set it to null I get exception null values are not allowed. Then how can I solve this problem with illegal characters ?

This is as short as possible version, try it:
XslCompiledTransform xsltTrans = new XslCompiledTransform();
string htmlResult;
string xmlContents = #"L:\ProjectGroup\GK\XML documents\Parent-Child.xml";
public String getHTMLresult()
{
xsltTrans.Load(#"L:\ProjectGroup\GK\XML documents\blah.xsl");
StringWriter sw = new StringWriter();
XmlTextWriter xw = new XmlTextWriter(sw);
xsltTrans.Transform(xmlContents, null, xw);
htmlResult = sw.ToString();
return htmlResult;
}

Related

Xml file not opening

I am developing C# application, but I encountered a problem while typing into xml file. Let me show the code first:
Company comp = new Company();
comp.CompanyID = comboBox1.SelectedValue.ToString();
comp.CompanyName = comboBox1.Text;
comp.Serial = strEncryptedData;
comp.ListProduct = ll;
XmlDocument xDoc = new XmlDocument();
using (StringWriter stringWriter = new StringWriter())
{
XmlSerializer serializer = new XmlSerializer(typeof(Company));
serializer.Serialize(stringWriter, comp);
xDoc.LoadXml(stringWriter.ToString());
}
string temp = xDoc.OuterXml;
MessageBox.Show(temp);
System.IO.StreamWriter sw = new System.IO.StreamWriter(#"c:\test.xml");
sw.WriteLine(temp);
sw.Flush();
sw.Close();
Program writes the file but when i try to open it in xml format, i recieve blank document, nothing inside. When i opened it in text editor i recieve this:
<?xml version="1.0" encoding="utf-16"?><CompanyXml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><CompanyName /><CompanyID>100</CompanyID><Serial>00000G2SB4BER9PSFJİ2GTVM2UC1VYEİ</Serial></CompanyXml>
It is the correct data I receive, but however cannot be opened as xml.
How can I format it? Or am I doing something wrong while writing it?
just remove this text encoding="utf-16" from your first line of xml then you will open the xml.
The issue appears to be with the encoding, removing utf-16 or changing to utf-8 corrects it.
You could try the StreamWriter constructor which takes an encoding to see if it saves the .xml with the correct encoding.
For example:
StreamWriter sw = new StreamWriter(#"c:\test.xml", Encoding.UTF8);
However, i found some other way to solve this issue after you guys pointed out utf format issue.
First of all we create a class which extends to StringWriter
public class Utf8StringWriter : StringWriter
{
public override Encoding Encoding
{
get { return Encoding.UTF8; }
}
}
Then we edit code into this by modifying StringWriter:
Company comp = new Company();
comp.CompanyID = comboBox1.SelectedValue.ToString();
comp.CompanyName = comboBox1.Text;
comp.Serial = strEncryptedData;
comp.ListProduct = ll;
XmlDocument xDoc = new XmlDocument();
using (StringWriter stringWriter = new Utf8StringWriter())
{
XmlSerializer serializer = new XmlSerializer(typeof(Company));
serializer.Serialize(stringWriter, comp);
StreamWriter sw = new StreamWriter(#"c:\text.xml");
sw.WriteLine(stringWriter);
sw.Flush();
sw.Close();
}
Regards...

XML Serialization to String

I'm trying to serialize an object into a string. Here is the code:
XmlSerializer xmlSerializer = new XmlSerializer(data.GetType());
StringWriter textWriter = new StringWriter();
xmlSerializer.Serialize(textWriter, data);
var xml = textWriter.ToString();
This works but "\r\n" are part of the string. I want to perform an XSLT transform with this string. That doesn't work because of the "\r\n" characters.
Here is the transform code:
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(xsltPath);
using (XmlReader xmlReader = System.Xml.XmlReader.Create(new StringReader(xmlString)))
{
transform.Transform(xmlReader, xmlWriter);
...
}
How to I go about this?
Simply replace those \r\ns with \n then use XSLT
var xml = textWriter.ToString().Replace("\r\n", "\n");

Format XML string to print friendly XML string

I have an XML string as such:
<?xml version='1.0'?><response><error code='1'> Success</error></response>
There are no lines between one element and another, and thus is very difficult to read. I want a function that formats the above string:
<?xml version='1.0'?>
<response>
<error code='1'> Success</error>
</response>
Without resorting to manually write the format function myself, is there any .Net library or code snippet that I can use offhand?
You will have to parse the content somehow ... I find using LINQ the most easy way to do it. Again, it all depends on your exact scenario. Here's a working example using LINQ to format an input XML string.
string FormatXml(string xml)
{
try
{
XDocument doc = XDocument.Parse(xml);
return doc.ToString();
}
catch (Exception)
{
// Handle and throw if fatal exception here; don't just ignore them
return xml;
}
}
[using statements are ommitted for brevity]
Use XmlTextWriter...
public static string PrintXML(string xml)
{
string result = "";
MemoryStream mStream = new MemoryStream();
XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode);
XmlDocument document = new XmlDocument();
try
{
// Load the XmlDocument with the XML.
document.LoadXml(xml);
writer.Formatting = Formatting.Indented;
// Write the XML into a formatting XmlTextWriter
document.WriteContentTo(writer);
writer.Flush();
mStream.Flush();
// Have to rewind the MemoryStream in order to read
// its contents.
mStream.Position = 0;
// Read MemoryStream contents into a StreamReader.
StreamReader sReader = new StreamReader(mStream);
// Extract the text from the StreamReader.
string formattedXml = sReader.ReadToEnd();
result = formattedXml;
}
catch (XmlException)
{
// Handle the exception
}
mStream.Close();
writer.Close();
return result;
}
This one, from kristopherjohnson is heaps better:
It doesn't require an XML document header either.
Has clearer exceptions
Adds extra behaviour options: OmitXmlDeclaration = true, NewLineOnAttributes = true
Less lines of code
static string PrettyXml(string xml)
{
var stringBuilder = new StringBuilder();
var element = XElement.Parse(xml);
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.Indent = true;
settings.NewLineOnAttributes = true;
using (var xmlWriter = XmlWriter.Create(stringBuilder, settings))
{
element.Save(xmlWriter);
}
return stringBuilder.ToString();
}
The simple solution that is working for me:
XmlDocument xmlDoc = new XmlDocument();
StringWriter sw = new StringWriter();
xmlDoc.LoadXml(rawStringXML);
xmlDoc.Save(sw);
String formattedXml = sw.ToString();
Check the following link: How to pretty-print XML (Unfortunately, the link now returns 404 :()
The method in the link takes an XML string as an argument and returns a well-formed (indented) XML string.
I just copied the sample code from the link to make this answer more comprehensive and convenient.
public static String PrettyPrint(String XML)
{
String Result = "";
MemoryStream MS = new MemoryStream();
XmlTextWriter W = new XmlTextWriter(MS, Encoding.Unicode);
XmlDocument D = new XmlDocument();
try
{
// Load the XmlDocument with the XML.
D.LoadXml(XML);
W.Formatting = Formatting.Indented;
// Write the XML into a formatting XmlTextWriter
D.WriteContentTo(W);
W.Flush();
MS.Flush();
// Have to rewind the MemoryStream in order to read
// its contents.
MS.Position = 0;
// Read MemoryStream contents into a StreamReader.
StreamReader SR = new StreamReader(MS);
// Extract the text from the StreamReader.
String FormattedXML = SR.ReadToEnd();
Result = FormattedXML;
}
catch (XmlException)
{
}
MS.Close();
W.Close();
return Result;
}
I tried:
internal static void IndentedNewWSDLString(string filePath)
{
var xml = File.ReadAllText(filePath);
XDocument doc = XDocument.Parse(xml);
File.WriteAllText(filePath, doc.ToString());
}
it is working fine as expected.
.NET 2.0 ignoring name resolving, and with proper resource-disposal, indentation, preserve-whitespace and custom encoding:
public static string Beautify(System.Xml.XmlDocument doc)
{
string strRetValue = null;
System.Text.Encoding enc = System.Text.Encoding.UTF8;
// enc = new System.Text.UTF8Encoding(false);
System.Xml.XmlWriterSettings xmlWriterSettings = new System.Xml.XmlWriterSettings();
xmlWriterSettings.Encoding = enc;
xmlWriterSettings.Indent = true;
xmlWriterSettings.IndentChars = " ";
xmlWriterSettings.NewLineChars = "\r\n";
xmlWriterSettings.NewLineHandling = System.Xml.NewLineHandling.Replace;
//xmlWriterSettings.OmitXmlDeclaration = true;
xmlWriterSettings.ConformanceLevel = System.Xml.ConformanceLevel.Document;
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(ms, xmlWriterSettings))
{
doc.Save(writer);
writer.Flush();
ms.Flush();
writer.Close();
} // End Using writer
ms.Position = 0;
using (System.IO.StreamReader sr = new System.IO.StreamReader(ms, enc))
{
// Extract the text from the StreamReader.
strRetValue = sr.ReadToEnd();
sr.Close();
} // End Using sr
ms.Close();
} // End Using ms
/*
System.Text.StringBuilder sb = new System.Text.StringBuilder(); // Always yields UTF-16, no matter the set encoding
using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(sb, settings))
{
doc.Save(writer);
writer.Close();
} // End Using writer
strRetValue = sb.ToString();
sb.Length = 0;
sb = null;
*/
xmlWriterSettings = null;
return strRetValue;
} // End Function Beautify
Usage:
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
xmlDoc.XmlResolver = null;
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load("C:\Test.svg");
string SVG = Beautify(xmlDoc);
Customizable Pretty XML output with UTF-8 XML declaration
The following class definition gives a simple method to convert an input XML string into formatted output XML with the xml declaration as UTF-8. It supports all the configuration options that the XmlWriterSettings class offers.
using System;
using System.Text;
using System.Xml;
using System.IO;
namespace CJBS.Demo
{
/// <summary>
/// Supports formatting for XML in a format that is easily human-readable.
/// </summary>
public static class PrettyXmlFormatter
{
/// <summary>
/// Generates formatted UTF-8 XML for the content in the <paramref name="doc"/>
/// </summary>
/// <param name="doc">XmlDocument for which content will be returned as a formatted string</param>
/// <returns>Formatted (indented) XML string</returns>
public static string GetPrettyXml(XmlDocument doc)
{
// Configure how XML is to be formatted
XmlWriterSettings settings = new XmlWriterSettings
{
Indent = true
, IndentChars = " "
, NewLineChars = System.Environment.NewLine
, NewLineHandling = NewLineHandling.Replace
//,NewLineOnAttributes = true
//,OmitXmlDeclaration = false
};
// Use wrapper class that supports UTF-8 encoding
StringWriterWithEncoding sw = new StringWriterWithEncoding(Encoding.UTF8);
// Output formatted XML to StringWriter
using (XmlWriter writer = XmlWriter.Create(sw, settings))
{
doc.Save(writer);
}
// Get formatted text from writer
return sw.ToString();
}
/// <summary>
/// Wrapper class around <see cref="StringWriter"/> that supports encoding.
/// Attribution: http://stackoverflow.com/a/427737/3063884
/// </summary>
private sealed class StringWriterWithEncoding : StringWriter
{
private readonly Encoding encoding;
/// <summary>
/// Creates a new <see cref="PrettyXmlFormatter"/> with the specified encoding
/// </summary>
/// <param name="encoding"></param>
public StringWriterWithEncoding(Encoding encoding)
{
this.encoding = encoding;
}
/// <summary>
/// Encoding to use when dealing with text
/// </summary>
public override Encoding Encoding
{
get { return encoding; }
}
}
}
}
Possibilities for further improvement:-
An additional method GetPrettyXml(XmlDocument doc, XmlWriterSettings settings) could be created that allows the caller to customize the output.
An additional method GetPrettyXml(String rawXml) could be added that supports parsing raw text, rather than have the client use the XmlDocument. In my case, I needed to manipulate the XML using the XmlDocument, hence I didn't add this.
Usage:
String myFormattedXml = null;
XmlDocument doc = new XmlDocument();
try
{
doc.LoadXml(myRawXmlString);
myFormattedXml = PrettyXmlFormatter.GetPrettyXml(doc);
}
catch(XmlException ex)
{
// Failed to parse XML -- use original XML as formatted XML
myFormattedXml = myRawXmlString;
}
Check the following link: Format an XML file so it looks nice in C#
// Format the XML text.
StringWriter string_writer = new StringWriter();
XmlTextWriter xml_text_writer = new XmlTextWriter(string_writer);
xml_text_writer.Formatting = Formatting.Indented;
xml_document.WriteTo(xml_text_writer);
// Display the result.
txtResult.Text = string_writer.ToString();
It is possible to pretty-print an XML string via a streaming transformation with XmlWriter.WriteNode(XmlReader, true). This method
copies everything from the reader to the writer and moves the reader to the start of the next sibling.
Define the following extension methods:
public static class XmlExtensions
{
public static string FormatXml(this string xml, bool indent = true, bool newLineOnAttributes = false, string indentChars = " ", ConformanceLevel conformanceLevel = ConformanceLevel.Document) =>
xml.FormatXml( new XmlWriterSettings { Indent = indent, NewLineOnAttributes = newLineOnAttributes, IndentChars = indentChars, ConformanceLevel = conformanceLevel });
public static string FormatXml(this string xml, XmlWriterSettings settings)
{
using (var textReader = new StringReader(xml))
using (var xmlReader = XmlReader.Create(textReader, new XmlReaderSettings { ConformanceLevel = settings.ConformanceLevel } ))
using (var textWriter = new StringWriter())
{
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
xmlWriter.WriteNode(xmlReader, true);
return textWriter.ToString();
}
}
}
And now you will be able to do:
var inXml = #"<?xml version='1.0'?><response><error code='1'> Success</error></response>";
var newXml = inXml.FormatXml(indentChars : "", newLineOnAttributes : false); // Or true, if you prefer
Console.WriteLine(newXml);
Which prints
<?xml version='1.0'?>
<response>
<error code="1"> Success</error>
</response>
Notes:
Other answers load the XML into some Document Object Model such as XmlDocument or XDocument/XElement, then re-serialize the DOM with indentation enabled.
This streaming solution completely avoids the added memory overhead of a DOM.
In your question you do not add any indentation for the nested <error code='1'> Success</error> node, so I set indentChars : "". Generally an indentation of two spaces per level of nesting is customary.
Attribute delimiters will be unconditionally transformed to double-quotes if currently single-quotes. (I believe this is true of other answers as well.)
Passing conformanceLevel : ConformanceLevel.Fragment allows strings containing sequences of XML fragments to be formatted.
Other than ConformanceLevel.Fragment, the input XML string must be well-formed. If it is not, XmlReader will throw an exception.
Demo fiddle here.
if you load up the XMLDoc I'm pretty sure the .ToString() function posses an overload for this.
But is this for debugging? The reason that it is sent like that is to take up less space (i.e stripping unneccessary whitespace from the XML).
Hi why don't you just try this:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = false;
....
....
xmlDoc.Save(fileName);
PreserveWhitespace = false; that option can be used xml beautifier as well.

What is the simplest way to get indented XML with line breaks from XmlDocument?

When I build XML up from scratch with XmlDocument, the OuterXml property already has everything nicely indented with line breaks. However, if I call LoadXml on some very "compressed" XML (no line breaks or indention) then the output of OuterXml stays that way. So ...
What is the simplest way to get beautified XML output from an instance of XmlDocument?
Based on the other answers, I looked into XmlTextWriter and came up with the following helper method:
static public string Beautify(this XmlDocument doc)
{
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings
{
Indent = true,
IndentChars = " ",
NewLineChars = "\r\n",
NewLineHandling = NewLineHandling.Replace
};
using (XmlWriter writer = XmlWriter.Create(sb, settings)) {
doc.Save(writer);
}
return sb.ToString();
}
It's a bit more code than I hoped for, but it works just peachy.
As adapted from Erika Ehrli's blog, this should do it:
XmlDocument doc = new XmlDocument();
doc.LoadXml("<item><name>wrench</name></item>");
// Save the document to a file and auto-indent the output.
using (XmlTextWriter writer = new XmlTextWriter("data.xml", null)) {
writer.Formatting = Formatting.Indented;
doc.Save(writer);
}
Or even easier if you have access to Linq
try
{
RequestPane.Text = System.Xml.Linq.XElement.Parse(RequestPane.Text).ToString();
}
catch (System.Xml.XmlException xex)
{
displayException("Problem with formating text in Request Pane: ", xex);
}
A shorter extension method version
public static string ToIndentedString( this XmlDocument doc )
{
var stringWriter = new StringWriter(new StringBuilder());
var xmlTextWriter = new XmlTextWriter(stringWriter) {Formatting = Formatting.Indented};
doc.Save( xmlTextWriter );
return stringWriter.ToString();
}
If the above Beautify method is being called for an XmlDocument that already contains an XmlProcessingInstruction child node the following exception is thrown:
Cannot write XML declaration.
WriteStartDocument method has already
written it.
This is my modified version of the original one to get rid of the exception:
private static string beautify(
XmlDocument doc)
{
var sb = new StringBuilder();
var settings =
new XmlWriterSettings
{
Indent = true,
IndentChars = #" ",
NewLineChars = Environment.NewLine,
NewLineHandling = NewLineHandling.Replace,
};
using (var writer = XmlWriter.Create(sb, settings))
{
if (doc.ChildNodes[0] is XmlProcessingInstruction)
{
doc.RemoveChild(doc.ChildNodes[0]);
}
doc.Save(writer);
return sb.ToString();
}
}
It works for me now, probably you would need to scan all child nodes for the XmlProcessingInstruction node, not just the first one?
Update April 2015:
Since I had another case where the encoding was wrong, I searched for how to enforce UTF-8 without BOM. I found this blog post and created a function based on it:
private static string beautify(string xml)
{
var doc = new XmlDocument();
doc.LoadXml(xml);
var settings = new XmlWriterSettings
{
Indent = true,
IndentChars = "\t",
NewLineChars = Environment.NewLine,
NewLineHandling = NewLineHandling.Replace,
Encoding = new UTF8Encoding(false)
};
using (var ms = new MemoryStream())
using (var writer = XmlWriter.Create(ms, settings))
{
doc.Save(writer);
var xmlString = Encoding.UTF8.GetString(ms.ToArray());
return xmlString;
}
}
XmlTextWriter xw = new XmlTextWriter(writer);
xw.Formatting = Formatting.Indented;
public static string FormatXml(string xml)
{
try
{
var doc = XDocument.Parse(xml);
return doc.ToString();
}
catch (Exception)
{
return xml;
}
}
A simple way is to use:
writer.WriteRaw(space_char);
Like this sample code, this code is what I used to create a tree view like structure using XMLWriter :
private void generateXML(string filename)
{
using (XmlWriter writer = XmlWriter.Create(filename))
{
writer.WriteStartDocument();
//new line
writer.WriteRaw("\n");
writer.WriteStartElement("treeitems");
//new line
writer.WriteRaw("\n");
foreach (RootItem root in roots)
{
//indent
writer.WriteRaw("\t");
writer.WriteStartElement("treeitem");
writer.WriteAttributeString("name", root.name);
writer.WriteAttributeString("uri", root.uri);
writer.WriteAttributeString("fontsize", root.fontsize);
writer.WriteAttributeString("icon", root.icon);
if (root.children.Count != 0)
{
foreach (ChildItem child in children)
{
//indent
writer.WriteRaw("\t");
writer.WriteStartElement("treeitem");
writer.WriteAttributeString("name", child.name);
writer.WriteAttributeString("uri", child.uri);
writer.WriteAttributeString("fontsize", child.fontsize);
writer.WriteAttributeString("icon", child.icon);
writer.WriteEndElement();
//new line
writer.WriteRaw("\n");
}
}
writer.WriteEndElement();
//new line
writer.WriteRaw("\n");
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
}
This way you can add tab or line breaks in the way you are normally used to, i.e. \t or \n
When implementing the suggestions posted here, I had trouble with the text encoding. It seems the encoding of the XmlWriterSettings is ignored, and always overridden by the encoding of the stream. When using a StringBuilder, this is always the text encoding used internally in C#, namely UTF-16.
So here's a version which supports other encodings as well.
IMPORTANT NOTE: The formatting is completely ignored if your XMLDocument object has its preserveWhitespace property enabled when loading the document. This had me stumped for a while, so make sure not to enable that.
My final code:
public static void SaveFormattedXml(XmlDocument doc, String outputPath, Encoding encoding)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = "\t";
settings.NewLineChars = "\r\n";
settings.NewLineHandling = NewLineHandling.Replace;
using (MemoryStream memstream = new MemoryStream())
using (StreamWriter sr = new StreamWriter(memstream, encoding))
using (XmlWriter writer = XmlWriter.Create(sr, settings))
using (FileStream fileWriter = new FileStream(outputPath, FileMode.Create))
{
if (doc.ChildNodes.Count > 0 && doc.ChildNodes[0] is XmlProcessingInstruction)
doc.RemoveChild(doc.ChildNodes[0]);
// save xml to XmlWriter made on encoding-specified text writer
doc.Save(writer);
// Flush the streams (not sure if this is really needed for pure mem operations)
writer.Flush();
// Write the underlying stream of the XmlWriter to file.
fileWriter.Write(memstream.GetBuffer(), 0, (Int32)memstream.Length);
}
}
This will save the formatted xml to disk, with the given text encoding.
If you have a string of XML, rather than a doc ready for use, you can do it this way:
var xmlString = "<xml>...</xml>"; // Your original XML string that needs indenting.
xmlString = this.PrettifyXml(xmlString);
private string PrettifyXml(string xmlString)
{
var prettyXmlString = new StringBuilder();
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);
var xmlSettings = new XmlWriterSettings()
{
Indent = true,
IndentChars = " ",
NewLineChars = "\r\n",
NewLineHandling = NewLineHandling.Replace
};
using (XmlWriter writer = XmlWriter.Create(prettyXmlString, xmlSettings))
{
xmlDoc.Save(writer);
}
return prettyXmlString.ToString();
}
A more simplified approach based on the accepted answer:
static public string Beautify(this XmlDocument doc) {
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings
{
Indent = true
};
using (XmlWriter writer = XmlWriter.Create(sb, settings)) {
doc.Save(writer);
}
return sb.ToString();
}
Setting the new line is not necessary. Indent characters also has the default two spaces so I preferred not to set it as well.
Set PreserveWhitespace to true before Load.
var document = new XmlDocument();
document.PreserveWhitespace = true;
document.Load(filename);

How to apply an XSLT Stylesheet in C#

I want to apply an XSLT Stylesheet to an XML Document using C# and write the output to a File.
I found a possible answer here: http://web.archive.org/web/20130329123237/http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=63
From the article:
XPathDocument myXPathDoc = new XPathDocument(myXmlFile) ;
XslTransform myXslTrans = new XslTransform() ;
myXslTrans.Load(myStyleSheet);
XmlTextWriter myWriter = new XmlTextWriter("result.html",null) ;
myXslTrans.Transform(myXPathDoc,null,myWriter) ;
Edit:
But my trusty compiler says, XslTransform is obsolete: Use XslCompiledTransform instead:
XPathDocument myXPathDoc = new XPathDocument(myXmlFile) ;
XslCompiledTransform myXslTrans = new XslCompiledTransform();
myXslTrans.Load(myStyleSheet);
XmlTextWriter myWriter = new XmlTextWriter("result.html",null);
myXslTrans.Transform(myXPathDoc,null,myWriter);
Based on Daren's excellent answer, note that this code can be shortened significantly by using the appropriate XslCompiledTransform.Transform overload:
var myXslTrans = new XslCompiledTransform();
myXslTrans.Load("stylesheet.xsl");
myXslTrans.Transform("source.xml", "result.html");
(Sorry for posing this as an answer, but the code block support in comments is rather limited.)
In VB.NET, you don't even need a variable:
With New XslCompiledTransform()
.Load("stylesheet.xsl")
.Transform("source.xml", "result.html")
End With
Here is a tutorial about how to do XSL Transformations in C# on MSDN:
http://support.microsoft.com/kb/307322/en-us/
and here how to write files:
http://support.microsoft.com/kb/816149/en-us
just as a side note: if you want to do validation too here is another tutorial (for DTD, XDR, and XSD (=Schema)):
http://support.microsoft.com/kb/307379/en-us/
i added this just to provide some more information.
This might help you
public static string TransformDocument(string doc, string stylesheetPath)
{
Func<string,XmlDocument> GetXmlDocument = (xmlContent) =>
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xmlContent);
return xmlDocument;
};
try
{
var document = GetXmlDocument(doc);
var style = GetXmlDocument(File.ReadAllText(stylesheetPath));
System.Xml.Xsl.XslCompiledTransform transform = new System.Xml.Xsl.XslCompiledTransform();
transform.Load(style); // compiled stylesheet
System.IO.StringWriter writer = new System.IO.StringWriter();
XmlReader xmlReadB = new XmlTextReader(new StringReader(document.DocumentElement.OuterXml));
transform.Transform(xmlReadB, null, writer);
return writer.ToString();
}
catch (Exception ex)
{
throw ex;
}
}
I would like to share this small piece of code which reads from Database and transforms using XSLT. On the top I also have used xslt-extensions which makes it little different than others.
Note: This is just a draft code and may need cleanup before using in production.
var schema = XDocument.Load(XsltPath);
using (var connection = new SqlConnection(ConnectionString))
{
connection.Open();
using (var command = new SqlCommand(Sql, connection))
{
var reader = command.ExecuteReader();
var dt = new DataTable(SourceNode);
dt.Load(reader);
string xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + Environment.NewLine;
using (var stringWriter = new StringWriter())
{
dt.WriteXml(stringWriter, true);
xml += stringWriter.GetStringBuilder().ToString();
}
XDocument transformedXml = new XDocument();
var xsltArgumentList = new XsltArgumentList();
xsltArgumentList.AddExtensionObject("urn:xslt-extensions", new XsltExtensions());
using (XmlWriter writer = transformedXml.CreateWriter())
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(schema.CreateReader());
xslt.Transform(XmlReader.Create(new StringReader(xml)), xsltArgumentList, writer);
}
var result = transformedXml.ToString();
}
}
XsltPath is path to your xslt file.
ConnectionString constant is pointing to your database.
Sql is your query.
SourceNode is node of each record in source xml.
Now the interesting part, please note the use of urn:xslt-extensions and new XsltExtensions() in above code. You can use this if need some complex computation which may not be possible in xslt. Following is a simple method to format date.
public class XsltExtensions
{
public string FormatDate(string dateString, string format)
{
DateTime date;
if (DateTime.TryParse(dateString, out date))
return date.ToString(format);
return dateString;
}
}
In XSLT file you can use it as below;
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="urn:xslt-extensions">
...
<myTag><xsl:value-of select="ext:FormatDate(record_date, 'yyyy-MM-dd')"/></myTag>
...
</xsl:stylesheet>

Categories

Resources