Search code examples
c#xmllinqwindows-phone-7windows-phone-7.1

How do I add a new element to the existing XML file on Windows Phone 7 using LINQ to XML?


For the last couple of hours I was struggling with LINQ to XML on Windows Phone 7. I simply just want to add new element to an existing XML file.

XElement newItem = new XElement("item",new XAttribute("id",3), 
                                new XElement("content","Buy groceries"),
                                new XElement("status","false"));

IsolatedStorageFile isFile = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream stream = new IsolatedStorageFileStream("/Items.xml", System.IO.FileMode.Open, isFile);

XDocument loadedDoc = XDocument.Load(stream);
loadedDoc.Add(newItem); 
loadedDoc.Save(stream);

Generally I'm experiencing very weird behavior. Sometimes I am getting an error "Operation not permitted on IsolatedStorageFileStream.". Sometimes it is "Root element is missing" and sometimes it is "Unexpected XML declaration. The XML declaration must be the first node in the document, and no white space characters are allowed to appear before it." If, for example, I would change System.IO.FileMode.Open to Create I would get "Root element is missing" but apart from that there doesn't seem to be any pattern according to which error occurs.

It all seems like its my XML file which causes the problem:

<?xml version="1.0" encoding="utf-8" ?>
<items>
   <item id="1">
      <content>Get groceries</content>
      <status>false</status>
   </item>
   <item id="2">
      <content>Wash your car</content>
      <status>true</status>
   </item>
</items> 

It doesn't get any simpler than that and I am absolutely sure I don't have any white spaces before the declaration in the actual XML file. And to make it all even more weird I have downloaded little sample application that uses the same technique of writing to XML file. When I try to run it I am getting a very familiar error:

Unexpected XML declaration. The XML declaration must be the first node in the document, and no white space characters are allowed to appear before it.

Here is link to that thread: http://mobileworld.appamundi.com/blogs/petevickers/archive/2010/12/06/windows-phone-7-linq-to-xml-corruption.aspx/

Yesterday I installed Windows Phone SDK 7.1 BETA. Could that be causing the problem?


It seems like the problem is with locating xml file in isolated storage. I have created completely new project and new xml file inside.

Thats the only code I have:

// Constructor
public MainPage()
{
    InitializeComponent();
    var isFile = IsolatedStorageFile.GetUserStoreForApplication();
    var stream = isFile.OpenFile("file.xml", System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite);
}  

I'am still getting: Operation not permitted on IsolatedStorageFileStream. I have tried going into properties of file.xml changing Built action and copy to output directory but that didn't work. I tried adding:

isFile.Dispose();

I also tried adding conditional statement:

if (isFile.FileExists("file.xml"))...

But he couldn't find the file.

I have never been so stuck in my life. Please advice me what else can i try.


Solution

  • You're trying to save to the same stream you loaded from - but without "rewinding" it to the start. I don't know whether isolated storage streams are seekable, but you can try just changing the code to:

    XDocument loadedDoc = XDocument.Load(stream);
    loadedDoc.Add(newItem);
    stream.Position = 0;
    loadedDoc.Save(stream);
    

    Note that while we don't need to reset the size of stream in this case as we're adding content, in other cases you might need to do so in order to avoid "leftover" bits at the end of the file.

    Alternatively, load the document and close the stream, then open up a new stream to the same file. Note that you should use using statements to close the streams after each use, e.g.

    using (var isFile = IsolatedStorageFile.GetUserStoreForApplication())
    {
        XDocument loadedDoc;
        using (var stream = isFile.OpenFile("/Items.xml", FileMode.Open))
        {
           loadedDoc = XDocument.Load(stream);
        }
        loadedDoc.Add(newItem); 
        using (var stream = isFile.OpenFile("/Items.xml", FileMode.Create))
        {
           loadedDoc.Save(stream);
        } 
    }