I am trying to serialize my Report class info to an XML. At this point I think all of the serialize and deserialize code works, but for the initial write, I'm having trouble performing the serialize, because the XML file doesn't exist yet.
for an empty text file, i can use:
StreamWriter sw = File.CreateText(#"path");
sw.Close();
this is my code block for the serializing. the exception (Directory not found) is getting thrown on the StreamWriter line. I'd like to simply add an if(!File.Exists(xmlPath))...create empty XML. Or maybe there is a more correct way to do this.
public void SerializeToXML(Report newReport)
{
XmlSerializer serializer = new XmlSerializer(typeof(Report));
TextWriter textWriter = new StreamWriter(xmlPath);
serializer.Serialize(textWriter, newReport);
textWriter.Close();
}
The StreamWriter(String) constructor will create the file if it does not already exist:
If the file exists, it is overwritten; otherwise, a new file is created.
However, it will not create any inexistent directories in your path.
DirectoryNotFoundException: The specified path is invalid, such as being on an unmapped drive.
To create any required directories, you can include the following code (at the beginning of your SerializeToXML method):
var dir = Path.GetDirectoryName(xmlPath);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
First to make sure the directory exist you can use:
Directory.CreateDirectory(#"c:\directory\subdirectory");
You don't have to check if directory already exist.
A easy way to convert public classes to XML is to use the following snippet:
public static string ToXml<T>(T obj)
{
using (var ms = new MemoryStream())
using (var sr = new StreamReader(ms))
{
var xmlSer = new XmlSerializer(typeof(T));
xmlSer.Serialize(ms, obj);
ms.Seek(0, SeekOrigin.Begin);
return sr.ReadToEnd();
}
}
Then you could just use the following code to write it to a file:
var xmlString = Util.ToXml(report);
File.WriteAllText(#"path", xmlString);
(this example is without error handling)
Also, in your code you forgot to close/dispose the TextWriter. I would recommend using the using-statement to handle it for you.
CreateText, and the StreamWriter, will create files if they don't exist, but they won't create directories that don't already exist for you. Is your path correct?
Try Checking with a Directory.Exists(Path.GetDirectoryName(xmlPath)).
Related
I have been fiddling with this problem for the past hour so I thought you guys may be able to help on a Friday afternoon!
Problem
I am trying to edit an XML file in localstorage but can't figure out how to edit the existing file and re-save the file. The edit I have made it to remove a certain node from the XML.
Code
Here is the method that does all the work.
This first code snippet was already in the code and basically creates the XML file and saves it to localstorage.:
protected byte[] CreateFileData(PortableBusinessObjects.Location location, string geoObjectFilename)
{
byte[] fileData = null;
var xmlFile = System.IO.Path.GetFileNameWithoutExtension(geoObjectFilename) + ".xml";
var zipFile = System.IO.Path.GetFileNameWithoutExtension(geoObjectFilename) + ".zip";
using (IsolatedStorageFileStream fileStream = localStorage.CreateFile(xmlFile))
{
XmlWriter writer = XmlWriter.Create(fileStream);
if (location.GetType() == typeof(PortableBusinessObjects.Shape))
_xmlShapeSerializer.Serialize(writer, location);
else if (location.GetType() == typeof(PortableBusinessObjects.Point))
_xmlPointSerializer.Serialize(writer, location);
fileStream.Flush();
fileStream.Close();
}
}
This is my attempt at overwriting the saved file (Doesn't work):
using (IsolatedStorageFileStream doc = localStorage.OpenFile(xmlFile, FileMode.Open))
{
System.Xml.Linq.XDocument test = System.Xml.Linq.XDocument.Load(doc);
test.Descendants("Time").Remove();
XmlWriter writer = XmlWriter.Create(doc);
doc.Flush();
doc.Close();
}
Question
Where do I place my code that removes the "Time" nodes and saves the file?
Your saving code doesn't do any saving - you just create an XmlWriter and do nothing with it.
There are various methods built into XDocument than can help you here. While you could pass your XmlWriter to it, you can actually save directly to the stream:
test.Save(doc);
Note you will need to move to the beginning of the stream before writing to it - loading your XML will have read to the end:
doc.Position = 0;
You should use the IsolatedStorageFileStream together with the StreamWriter.
See How to: Read and Write to Files in Isolated Storage
With XDocument you then have to Save() the new contents to the stream.
In C# am trying to check to see if an XML file is created, if not create the file and then create the xml declaration, a comment and a parent node.
When I try to load it, it gives me this error:
"The process cannot access the file 'C:\FileMoveResults\Applications.xml' because it is being used by another process."
I checked the task manager to ensure it wasn't open and sure enough there were no open applications of it. Any ideas of what's going on?
Here is the code I am using:
//check for the xml file
if (!File.Exists(GlobalVars.strXMLPath))
{
//create the xml file
File.Create(GlobalVars.strXMLPath);
//create the structure
XmlDocument doc = new XmlDocument();
doc.Load(GlobalVars.strXMLPath);
//create the xml declaration
XmlDeclaration xdec = doc.CreateXmlDeclaration("1.0", null, null);
//create the comment
XmlComment xcom = doc.CreateComment("This file contains all the apps, versions, source and destination paths.");
//create the application parent node
XmlNode newApp = doc.CreateElement("applications");
//save
doc.Save(GlobalVars.strXMLPath);
Here is the code I ended up using to fix this issue:
//check for the xml file
if (!File.Exists(GlobalVars.strXMLPath))
{
using (XmlWriter xWriter = XmlWriter.Create(GlobalVars.strXMLPath))
{
xWriter.WriteStartDocument();
xWriter.WriteComment("This file contains all the apps, versions, source and destination paths.");
xWriter.WriteStartElement("application");
xWriter.WriteFullEndElement();
xWriter.WriteEndDocument();
}
File.Create() returns a FileStream that locks the file until it's closed.
You don't need to call File.Create() at all; doc.Save() will create or overwrite the file.
I would suggest something like this:
string filePath = "C:/myFilePath";
XmlDocument doc = new XmlDocument();
if (System.IO.File.Exists(filePath))
{
doc.Load(filePath);
}
else
{
using (XmlWriter xWriter = XmlWriter.Create(filePath))
{
xWriter.WriteStartDocument();
xWriter.WriteStartElement("Element Name");
xWriter.WriteEndElement();
xWriter.WriteEndDocument();
}
//OR
XmlDeclaration xdec = doc.CreateXmlDeclaration("1.0", null, null);
XmlComment xcom = doc.CreateComment("This file contains all the apps, versions, source and destination paths.");
XmlNode newApp = doc.CreateElement("applications");
XmlNode newApp = doc.CreateElement("applications1");
XmlNode newApp = doc.CreateElement("applications2");
doc.Save(filePath); //save a copy
}
The reason your code is currently having problems is because of: File.Create creates the file and opens the stream to the file, and then you never make use of it (never close it) on this line:
//create the xml file
File.Create(GlobalVars.strXMLPath);
if you did something like
//create the xml file
using(Stream fStream = File.Create(GlobalVars.strXMLPath)) { }
Then you would not get that in use exception.
As a side note XmlDocument.Load will not create a file, only work with an already create one
You could create a stream, setting the FileMode to FileMode.Create and then use the stream to save the Xml to the path specified.
using (System.IO.Stream stream = new System.IO.FileStream(GlobalVars.strXMLPath, FileMode.Create))
{
XmlDocument doc = new XmlDocument();
...
doc.Save(stream);
}
I am trying to insert data in existing XMl file. I have the following code.
string file = MapPath("~/XMLFile1.xml");
XDocument doc;
//Verify whether a file is exists or not
if (!System.IO.File.Exists(file))
{
doc = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"),
new System.Xml.Linq.XElement("Contacts"));
}
else
{
doc = XDocument.Load(file);
}
foreach (var c in MyContactsLst)
{
//var contactsElement = new XElement("Contacts",
var contactsElement = new XElement("Contact",
new XElement("Name", c.FirstOrDefault().DisplayName),
new XElement("PhoneNumber", c.FirstOrDefault().PhoneNumber.ToString()),
new XElement("Email", "abc#abc.com"));
doc.Root.Add(contactsElement);
doc.Save(file);
}
The first issue is in first line of code i.e. MapPath("~/XMLFile1.xml"); It gives me an error
The name 'MapPath' does not exist in the current context
The second issue is in doc.Save(file); It gives me an error
The best overloaded method match for 'System.Xml.Linq.XDocument.Save(System.IO.Stream)' has some invalid arguments
I have refer this question How to insert data into an existing xml file in asp.net?
I am learning XML. So, how can I solve this?
The reason why MapPath does not exist in the current context is because it is a method of HttpServerUtility class, and as far as I know, it is not supported on Windows Phone.
Try loading the XDocument like this:
XDocument xdocument = XDocument.Load("XMLFile1.xml");
EDIT: You were having an error saving the document. Here is an answer from a related thread:
using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (Stream stream = storage.CreateFile("data.xml"))
{
doc.Save(stream);
}
}
Adding onto Kajzer's answer, here is another alternative that may be easier to grasp and use for saving an XDocument:
string path = "[some path]";
using (Stream stream = File.Create(path))
{
doc.Save(stream);
}
There is just one using statement, and you'll only need the System.IO class as it provides both the Stream and File classes for you to use - making this the most straightforward and easiest to understand solution.
I'm attempting to read from an XML document in WP7 and have run into a weird error that I simply just don't get, when I run my program from the first time after restarting the WP7 emulator but if I run it in debug without closing the emulator it gives me the runtime error: 'XmlException was unhandled Cannot find file 'appdata.xml' in the application xap package.' which is strange because I check to see if the file exists first:
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (store.FileExists("appdata.xml"))
{
XDocument loadedData = XDocument.Load("appdata.xml"); // <-- runtime error
//code for parsing xml to variables
}
}
It enters the if statement so the file should exist but XDocument doesn't like it for some reason, anyone have any ideas?
For further reference here is how I am saving my data when I tap a button in an app, also the error does not occur if this function isn't called:
private void SaveData()
{
rulesData = new AppData(StartCashRule.Text, LandGoRule.Text, FreeParkingRule.Text, FullCircuitRule.Text, AuctionRule.Text);
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
IsolatedStorageFileStream ifStream = new IsolatedStorageFileStream("appdata.xml", FileMode.OpenOrCreate, store);
using (XmlWriter writer = XmlWriter.Create(ifStream))
{
writer.WriteStartDocument();
writer.WriteStartElement("myData");
writer.WriteElementString("Starting_Cash", rulesData.myStartingCash);
writer.WriteElementString("Land_on_Go_Data", rulesData.myLandOnGo);
writer.WriteElementString("Free_Parking_Data", rulesData.myFreeParking);
writer.WriteElementString("Full_Circuit_Data", rulesData.myFullCircuit);
writer.WriteElementString("Auction_Data", rulesData.myAuction);
writer.WriteEndElement();
writer.WriteEndDocument();
}
ifStream.Close();
}
}
Thanks - Ryan
You are passing to XDocument.Load the name "appdata.xml" without any reference to the IsolatedStorage store where the file really exists.
You should write something like this
XDocument loadedData = XDocument.Load(store.OpenFile("appdata.xml", FileMode.Open));
Thank you very much in advance
This is the original XML File
<my:Incident>
<my:Category>This is for Category</my:Category>
<my:Status>`Status is Close`</my:Status>
<my:Description>`This is the description part</my:Description>
</my:Incident>
and I would like to add other fields under my:Incident
This is an example of it:
<my:Incident>
<my:Category>This is for Category</my:Category>
<my:Status>`Status is Close`</my:Status>
<my:SummaryDescription>This is the summary</my:SummaryDescription>
<my:Description>`This is the description part</my:Description>
</my:Incident>
I tried to implemented but I got this error message:
The ':' character, hexadecimal value 0x3A, cannot be included in a name.
public void writerXMLTest(string fileName)
{
if (!File.Exists(fileName))
{
XmlTextWriter writer = new XmlTextWriter(fileName, null);
writer.WriteStartElement("my:Incident");
writer.WriteEndElement();
writer.Close();
}
XDocument doc = XDocument.Load(fileName);
XElement demoNode = new XElement("my:Incident");
demoNode.Add(new XElement("my:SummaryDescription", "Test Test"));
Console.WriteLine("I write it!!!!!");
}
I would appreciate if anyone can guide me where I did wrong in my code.
I modified the code a little. But now I'm not able to write it to the existing XML File
This is my code:
public void writerXMLTest(string fileName)
{
if (!File.Exists(fileName))
{
XmlTextWriter writer = new XmlTextWriter(fileName, null);
writer.WriteStartElement("Incident", "my");
writer.WriteEndElement();
writer.Close();
}
XDocument doc = XDocument.Load(fileName);
XElement demoNode = new XElement("SummaryDescription", "Test Test");
Console.WriteLine("I write it!!!!!");
}
This is wrong:
writer.WriteStartElement("my:Incident");
This is right:
writer.WriteStartElement("Incident", "blablablaSpace:my");
Edit:
writer.WriteStartElement("Incident", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2005-09-22T20:42:56:my");
There are several problems here. First your "original XML" is not valid because you have not defined the "my" namespace. Either you have not shown us the entire XML file, or you are hand-coding invalid XML. Don't do that.
I'm not able to write it to the existing XML File.
What does "I'm not able" mean? It throws an exception? What is the exception? Or do you mean your file is unchanged after running your code? That is unsurprising because your code doesn't actually do anything.
XDocument doc = XDocument.Load(fileName);
This loads your XML file from disk... and then does nothing with it. It doesn't change the file.
XElement demoNode = new XElement("SummaryDescription", "Test Test");
This creates a new XML element, totally unrelated to doc, the original file, or to anything else... and then throws it away without doing anything with it. You have not added it anywhere or saved anything to a file.
and I would like to add other fields under my:Incident
If you want to add demoNode to the file, you first must find the Incident node:
XElement e = doc.Descendants(XName.Get("Incident", nameSpace)).FirstOrDefault<XElement>();
Add your new element to it:
if (e != null)
{
e.Add( new XElement(XName.Get("SummaryDescription", nameSpace), "Test Test") );
}
Then save the changed document
doc.Save(fileName);
Your "my:" prefix is a namespace. You must use TagName = "Incident", Namespace="my".
Microsoft provides documentation on using XmlTextWriter with namespaces
http://msdn.microsoft.com/en-us/library/cfche0ka(v=vs.80).aspx