I want to keep a single XmlDocument object in a class and let methods make changes to it and save it.
using (FileStream fs = new FileStream(#"D:\Diary.xml",
FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(fs);
// ... make some changes here
xmlDoc.Save(fs);
}
The above code makes two copies of the xml structure inside the file.
Try
fs.SetLength(0);
before Save call
Add:
fs.Position = 0;
before the Save call.
It seems a bit strange that fs.Position from Foole's solution didn't work.
An equivalent would be
fs.Seek(0, SeekOrigin.Begin);
Alternatively
instead of using the same filestream:
//OrigPath is the path you're using for the FileReader
System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(OrigPath);
xmlDoc.Save(writer);
writer.Close();
Alternatively even this would work...
XmlDocument xmlDoc = new XmlDocument( );
xmlDoc.Load( #"D:\Diary.xml" );
//.... make some changes here
XmlText node = xmlDoc.CreateTextNode( "test" );
xmlDoc.DocumentElement.AppendChild( node );
xmlDoc.Save( #"D:\Diary.xml" );
Related
In our software, we can draw or edit shapes and save it as a xaml.
Then, we want to load it(this xaml file) asynchronously, we used LoadAsync() method to do this, now the question is we can write x:SynchronousMode='Async' to the file manually, but how can we save this attribute to a xaml file directly(when we serialize it)?
The instruction from MSDN:
In order for LoadAsync to load XAML input asynchronously, the root
element in the XAML input must contain the attribute and value
x:SynchronousMode="Async".
Finally,I didn't find the way to add the attribute to the object, then I used a tack-handed way to solve this problem by the following code:
StringBuilder sb = new StringBuilder();
var xmlWriter = XmlWriter.Create(sb, settings);
XamlWriter.Save(Window, xmlWriter);
var str = sb.ToString().Insert(11, "assembly:SynchronousMode=\"Async\" ");
if (!File.Exists(path))
{
FileStream tmp = File.Create(path);
tmp.Close();
}
FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(str);
sw.Flush();
sw.Close();
fs.Close();
Insert it to the string that we convert object into with XamlWriter directly, and then save the string as a xaml file.
I have a strange issue with my XmlDocument class.
I write some XML file with it, which works great.
And I have Save() method:
public void Save()
{
var xwSettings = new XmlWriterSettings
{
Encoding = new UTF8Encoding(false),
Indent = true,
IndentChars = "\t"
};
using (XmlWriter xw = XmlWriter.Create(new FileStream(this.FilePath, FileMode.Create), xwSettings))
{
XmlDocument.WriteTo(xw);
}
}
Like everyone sees, I'm using "using" which should give the xml free :)
But if I try to read this file directly after calling Save() I get the exception:
The process can not access the file "___.xml", because it's already in use by another process.
Can someone explain that to me and give me a solution for it?
Kind regards
You are not disposing your file stream. Try changing your code like this.
using (var xmlStream = new FileStream(this.FilePath, FileMode.Create))
{
using (XmlWriter xw = XmlWriter.Create(xmlStream, xwSettings))
{
var xDoc = new XmlDocument();
xDoc.WriteTo(xw);
}
}
I'm using XDocument to update the XML file with Isolated Storage. However, after save the updated XML file, some extra characters are added automatically.
Here is my XML file before update:
<inventories>
<inventory>
<id>I001</id>
<brand>Apple</brand>
<product>iPhone 5S</product>
<price>750</price>
<description>The newest iPhone</description>
<barcode>1234567</barcode>
<quantity>75</quantity>
<inventory>
</inventories>
Then after the file is updated and saved, it becomes:
<inventories>
<inventory>
<id>I001</id>
<brand>Apple</brand>
<product>iPhone 5S</product>
<price>750</price>
<description>The best iPhone</description>
<barcode>1234567</barcode>
<quantity>7</quantity>
<inventory>
</inventories>ies>
I've spent a lot of time trying to find and fix the problem but no solutions were found. The solution in the post xdocument save adding extra characters cannot help me fix my problem.
Here's my C# code:
private void UpdateInventory(string id)
{
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = isf.OpenFile("inventories.xml", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
XDocument doc = XDocument.Load(stream);
var item = from c in doc.Descendants("inventory")
where c.Element("id").Value == id
select c;
foreach (XElement e in item)
{
e.Element("price").SetValue(txtPrice.Text);
e.Element("description").SetValue(txtDescription.Text);
e.Element("quantity").SetValue(txtQuantity.Text);
}
stream.Position = 0;
doc.Save(stream);
stream.Close();
NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
}
}
The most reliable way is to re-create it:
XDocument doc; // declare outside of the using scope
using (IsolatedStorageFileStream stream = isf.OpenFile("inventories.xml",
FileMode.Open, FileAccess.Read))
{
doc = XDocument.Load(stream);
}
// change the document here
using (IsolatedStorageFileStream stream = isf.OpenFile("inventories.xml",
FileMode.Create, // the most critical mode-flag
FileAccess.Write))
{
doc.Save(stream);
}
When I had a similar problem in Python, I discovered that I was overwriting the beginning of the file without truncating it afterwards.
Looking at your code, I'd say you might be doing the same:
stream.Position = 0;
doc.Save(stream);
stream.Close();
Try setting the stream length to its post-save location as per this answer:
stream.Position = 0;
doc.Save(stream);
stream.SetLength(stream.Position);
stream.Close();
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.