I have a function that translates a xml file using a xsl style sheet. It does the job fine; but when I want to delete that transformed file sometimes I get the following error: System.IO.IOException: The process cannot access the file
The function is like this:
XslTransform transform = new XslTransform();
transform.Load('xsl_style_sheet');
transform.Transform('fullpath/xmlfilename','fullpath/transformedFileName')
XElement xEle = XElement.Load('fullpath/transformedFileName');
I do what ever with the xEle and in the end I want to delete the 'fullpath/transformedFileName' but some times i get the dreaded System.IO.IOException: The process cannot access the file
Can any one please help. A million thanks
Use the XslCompiledTranform class (XslTranform is obsolete ) and the overload on Transform that accepts an XmlReader and XmlWriter. You can call Dispose on them, they will take care of closing and disposing the underlying stream.
// Load the style sheet.
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load("xsl_style_sheet");
// Create the writer.
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = "\t";
using(XmlWriter writer = XmlWriter.Create("fullpath/transformedFileName", settings))
{
using(XmlReader reader = XmlReader.Create("fullpath/xmlfilename"))
{
reader.MoveToContent();
xslt.Transform(reader, writer);
}
}
using(XmlReader reader = XmlReader.Create("fullpath/transformedFileName"))
{
XElement xEle = XElement.Load(reader);
// do all other stuff you need to do here
// after this the file will be closed
}
Related
I am writing to the file XML serialization of the object, generated by validator.MatchPossiblyValid(string input)method. First call, serializes and write to the file. However, the second call fails with an exception: System.InvalidOperationException: 'Token StartElement in state EndRootElement would result in an invalid XML document. Make sure that the ConformanceLevel setting is set to ConformanceLevel.Fragment or ConformanceLevel.Auto if you want to write an XML fragment. '
XmlSerializerNamespaces emptyNS = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var serializer = new XmlSerializer(typeof(PDPCustomerInfoInvalid));
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
//settings.Indent = true;
using (var stream = new System.IO.StreamWriter(args[1], true))
{
using (var writer = XmlWriter.Create(stream, settings))
{
serializer.Serialize(writer, validator.MatchPossiblyValid("STRING FOR PARSING"), emptyNS);
stream.Write(Environment.NewLine);
stream.Flush();
//Line below throws the exception
serializer.Serialize(writer, validator.MatchPossiblyValid("STRING FOR PARSING"), emptyNS);
stream.Write(Environment.NewLine);
stream.Flush();
}
}
You are trying to use a single XmlWriter to create an XML file with multiple root elements. However, the XML standard requires exactly one root element per XML document. Your XmlWriter is throwing the exception to indicate that the XML being created is invalid. (MCVE here.)
If you really need to concatenate two XML documents into a single file, you could use separate XmlWriters created with XmlWriterSettings.CloseOutput set to false:
using (var stream = new System.IO.StreamWriter(args[1], true))
{
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
//settings.Indent = true;
settings.CloseOutput = false;
using (var writer = XmlWriter.Create(stream, settings))
{
serializer.Serialize(writer, validator.MatchPossiblyValid("STRING FOR PARSING"), emptyNS);
}
stream.Write(Environment.NewLine);
stream.Flush();
using (var writer = XmlWriter.Create(stream, settings))
{
serializer.Serialize(writer, validator.MatchPossiblyValid("STRING FOR PARSING"), emptyNS);
}
//Line below throws the exception
stream.Write(Environment.NewLine);
stream.Flush();
}
Sample fiddle.
Or, better yet, don't do this at all, since an "XML Document" with multiple roots is, as stated above, not valid. Instead, serialize both objects inside some container element.
I'm trying to create an xml file. I already set the document and have a result with Xmlwriter when printing to console but when it comes to having an actual .xml file on my desktop I always end up with empty files. Clearly I'm missing something or forgetting something but can't tell on my own.
Below is the piece of my code where it all happens (not).
public void button1_Click(object sender, EventArgs e)
{
XmlDocument dddxml = new XmlDocument();
//XmlDeclaration xmldecl;
//xmldecl = dddxml.CreateXmlDeclaration("1.0", null, null);
//xmldecl.Encoding = "UTF-8";
//xmldecl.Standalone = "yes";
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
StringBuilder builder = new StringBuilder();
writer = XmlWriter.Create(builder, settings);
writer.WriteStartDocument();
writer.WriteStartElement("root");
BlockSelect(0);
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Close();
Console.WriteLine(builder.ToString());
writer = XmlWriter.Create("DddXml.Xml", settings);
dddxml.Save(writer);
File.Create(path);//declared elsewhere, valid file location string
}
You have created new XmlDocument here:
XmlDocument dddxml = new XmlDocument();
But you haven't populated it in the rest of the code and in fact you're not using it and writing xml to string builder using WriteStartDocument and WriteEndElement methods of XmlWriter.
Thus your dddxml remains empty, so when you're trying to save it like this:
dddxml.Save(writer);
, there is nothing to save and you're getting empty file.
So you have to choose - will you use XmlDocument or XmlWriter to create and save your xml.
As commented by #Charles Mager, File.Create() just makes an empty file.
You can try to write directly to the file instead of using StringBuilder. Here's a sample to directly write to the file using the XmlWriter:
XmlWriter writer = XmlWriter.Create("C:\\ddxml.xml", settings);
writer.WriteStartDocument();
writer.WriteStartElement("root");
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Close();
See that the file is written on C:\ddxml.xml.
If you want you can also use LINQ, it's easier :
XDocument doc = new XDocument();
XNamespace ns = "";
doc.Add(new XElement(ns + "root"));
doc.Save(#"C:\DddXml.Xml");
Using the following code:
XDocument transformedDoc = new XDocument();
using (XmlWriter writer = transformedDoc.CreateWriter())
{
XslCompiledTransform transform = new XslCompiledTransform();
//transform.Load(XmlReader.Create(new StringReader(HttpContext.Current.Server.MapPath("~/XML/CareLog.xsl"))));
transform.Load(HttpContext.Current.Server.MapPath("~/XML/CareLog.xsl"));
transform.Transform(doc.CreateReader(), writer);
}
I have some strings from a database that contain <br /> for a line return(as used elsewhere). Whatever I replace this with, Environment.NewLine, \n, etc it will never put line breaks in the transformed document.
EDIT
Replaced line breaks with \r\n and changed as per suggestion below:
var xslt = new XslCompiledTransform();
xslt.Load(HttpContext.Current.Server.MapPath("~/XML/CareLogresidenceSummary.xsl"));
var settings = xslt.OutputSettings.Clone();
settings.NewLineChars = "\n";
using (var reader = doc.CreateReader())
{
using (var writer = XmlWriter.Create(HttpContext.Current.Server.MapPath("~/BrowserTemp/CareLogResidenceSummary.xml"), settings))
{
xslt.Transform(reader, writer);
}
}
Still creates transformed document ok, but still does not put anything onto a new line. For reference I am renaming the transformed document with a .doc extension to open in word, the XML has the line breaks but not when opened in Word.
You should use "\r\n" for representing new lines.
There are two ways you can handle the newlines:
Set-up the writer to use specific characters when writing new lines using the NewLineChars option.
Instruct the writer not to modify the new lines using the NewLineHandling option
So you could modify your code as follows to preserve the new lines:
var xslt = new XslCompiledTransform();
xslt.Load(HttpContext.Current.Server.MapPath("~/XML/CareLog.xsl"));
var settings = xslt.OutputSettings.Clone();
settings.NewLineChars = "\n";
settings.NewLineHandling = NewLineHandling.Replace;
using (var reader = XmlReader.Create("example.xml"))
{
using (var writer = XmlWriter.Create("yourDoc.txt", settings))
{
xslt.Transform(reader, writer);
}
}
Note that I haven't run this. The only thing you'll need to do is get your file into the call to "XmlWriter.Create()".
I have an xmlwriter object used in a method. I'd like to dump this out to a file to read it. Is there a straightforward way to do this?
Thanks
Use this code
// Create the XmlDocument.
XmlDocument doc = new XmlDocument();
doc.LoadXml("<item><name>wrench</name></item>");
// Add a price element.
XmlElement newElem = doc.CreateElement("price");
newElem.InnerText = "10.95";
doc.DocumentElement.AppendChild(newElem);
// Save the document to a file and auto-indent the output.
XmlTextWriter writer = new XmlTextWriter(#"C:\data.xml", null);
writer.Formatting = Formatting.Indented;
doc.Save(writer);
As found on MSDN: http://msdn.microsoft.com/en-us/library/z2w98a50.aspx
One possibility is to set the XmlWriter to output to a text file:
using (var writer = XmlWriter.Create("dump.xml"))
{
...
}
Need to generate an html report from XML and corresponding XSL butI have to use memorystream instead of IO File write on server directories. For the most part I managed to create an xml
MemoryStream ms = new MemoryStream();
XmlWriterSettings wSettings = new XmlWriterSettings();
wSettings.Indent = true;
using(XmlWriter writer = XmlWriter.Create(ms,wSettings))
{
/**
creating xml here
**/
writer.Flush();
writer.Close();
}
return ms; // returning the memory stream to another function
// to create html
// This Function creates
protected string ConvertToHtml(MemoryStream xmlOutput)
{
XPathDocument document = new XPathDocument(xmlOutput);
XmlDocument xDoc = new XmlDocument();
xDoc.Load(xmlOutput);
StringWriter writer = new StringWriter();
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(reportDir + "MyXslFile.xsl");
transform.Transform(xDoc, null, writer);
xmlOutput.Position = 1;
StreamReader sr = new StreamReader(xmlOutput);
return sr.RearToEnd();
}
Somewhere along the line I am messing up with creating the HTML Report and cant figure out how to send that file to client end. I dont have much experience working with memorystream. So, any help would be greatly appreciated. Thank you.
You're completely bypassing your transform here:
// This Function creates
protected string ConvertToHtml(MemoryStream xmlOutput)
{
XPathDocument document = new XPathDocument(xmlOutput);
XmlDocument xDoc = new XmlDocument();
xDoc.Load(xmlOutput);
StringWriter writer = new StringWriter();
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(reportDir + "MyXslFile.xsl");
transform.Transform(xDoc, null, writer);
// These lines are the problem
//xmlOutput.Position = 1;
//StreamReader sr = new StreamReader(xmlOutput);
//return sr.RearToEnd();
return writer.ToString()
}
Also, calling Flush right before you call Close on a writer is redundant as Close implies a flush operation.
It is not clear to me what you want to achieve but using both XmlDocument and XPathDocument to load from the same memory stream does not make sense I think. And I would set the MemoryStream to Position 0 before loading from it so either have the function creating and writing to the memory stream ensure that it sets the Position to zero or do that before you call Load on the XmlDocument or before you create an XPathDocument, depending on what input tree model you want to use.