Xml gets corrupted each time I append a node

2019-08-11 15:26发布

问题:

I have an Xml file as:

<?xml version="1.0"?>
<hashnotes>
  <hashtags>
    <hashtag>#birthday</hashtag>
    <hashtag>#meeting</hashtag>
    <hashtag>#anniversary</hashtag>
  </hashtags>
  <lastid>0</lastid>
  <Settings>
    <Font>Arial</Font>
    <HashtagColor>red</HashtagColor>
    <passwordset>0</passwordset>
    <password></password>
  </Settings>
</hashnotes>

I then call a function to add a node in the xml,

The function is :

public static void CreateNoteNodeInXDocument(XDocument argXmlDoc, string argNoteText)
    {
       string lastId=((Convert.ToInt32(argXmlDoc.Root.Element("lastid").Value)) +1).ToString();
       string date = DateTime.Now.ToString("MM/dd/yyyy");
        argXmlDoc.Element("hashnotes").Add(new XElement("Note", new XAttribute("ID", lastId), new XAttribute("Date",date),new XElement("Text", argNoteText)));
        //argXmlDoc.Root.Note.Add new XElement("Text", argNoteText)
        List<string> hashtagList = Utilities.GetHashtagsFromText(argNoteText);

        XElement reqNoteElement = (from xml2 in argXmlDoc.Descendants("Note")
                            where xml2.Attribute("ID").Value == lastId
                            select xml2).FirstOrDefault();
        if (reqNoteElement != null)
        {
            foreach (string hashTag in hashtagList)
            {
                reqNoteElement.Add(new XElement("hashtag", hashTag));
            }
        }

        argXmlDoc.Root.Element("lastid").Value = lastId;
    }

After this I save the xml. Next time when I try to load the Xml, it fails with an exception: System.Xml.XmlException: 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 the code to load the XML:

private static XDocument hashNotesXDocument;
private static Stream hashNotesStream;

StorageFile hashNoteXml = await InstallationFolder.GetFileAsync("hashnotes.xml");
hashNotesStream = await hashNoteXml.OpenStreamForWriteAsync();
hashNotesXDocument = XDocument.Load(hashNotesStream);

and I save it using:

hashNotesXDocument.Save(hashNotesStream);

回答1:

You don't show all of your code, but it looks like you open the XML file, read the XML from it into an XDocument, edit the XDocument in memory, then write back to the opened stream. Since the stream is still open it will be positioned at the end of the file and thus the new XML will be appended to the file.

Suggest eliminating hashNotesXDocument and hashNotesStream as static variables, and instead open and read the file, modify the XDocument, then open and write the file using the pattern shown here.

I'm working only on desktop code (using an older version of .Net) so I can't test this, but something like the following should work:

    static async Task LoadUpdateAndSaveXml(Action<XDocument> editor)
    {
        XDocument doc;
        var xmlFile = await InstallationFolder.GetFileAsync("hashnotes.xml");
        using (var reader = new StreamReader(await xmlFile.OpenStreamForReadAsync()))
        {
            doc = XDocument.Load(reader);
        }        

        if (doc != null)
        {
            editor(doc);
            using (var writer = new StreamWriter(await xmlFile.OpenStreamForWriteAsync()))
            {
                // Truncate - https://stackoverflow.com/questions/13454584/writing-a-shorter-stream-to-a-storagefile
                if (writer.CanSeek && writer.Length > 0) 
                    writer.SetLength(0);
                doc.Save(writer);
            }
        }
    }

Also, be sure to create the file before using it.