Search code examples
c#xmllinq-to-xmlxmlwriter

Add new lines to XML file


I have a program that creates an XML log. First I check if the XML exists, and if not I use the following code to create it:

XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;

using (XmlWriter writer = XmlWriter.Create(myXMLLog, settings))
                    {
                    writer.WriteStartDocument();
                    writer.WriteComment("Comment here.");
                    writer.WriteStartElement("Batch");
                    writer.WriteAttributeString("ID", BatchID);
                    writer.WriteAttributeString("Date", now);
                    writer.WriteStartElement("Step");
                    writer.WriteElementString("Name", step);
                    writer.WriteElementString("Success", success);
                    writer.WriteElementString("Message", message);
                    writer.WriteStartElement("Transaction");
                    writer.WriteElementString("ID", transID);
                    writer.WriteElementString("Details", details);

                    writer.WriteEndElement();
                    writer.WriteEndDocument();
                }

This works as expected and creates the file:

<!--This log was created by the Application.-->
<Batch Date="1/22/2014 10:01:11 PM" ID="166bf0d2-3bd4-4353-b309-20b6d0d59a93">
<Step>
   <Name>Start Batch</Name>
   <Success>1</Success>
   <Message>Processing Batch</Message>
<Transaction>
   <ID>N/A</ID>
   <Details>N/A</Details>
</Transaction>
</Step>

So the second time around, it checks that the XML exists, it does, so instead of creating it should just add to it. I'm using the following code for this:

                XDocument xmlDoc = XDocument.Load(myXMLLog);
                XElement root = new XElement("Batch");

                root.Add(new XAttribute("ID", BatchID));
                root.Add(new XAttribute("Date", now));
                root.Add(new XElement("Step"));
                root.Add(new XAttribute("Name", step));
                root.Add(new XAttribute("Success", success));
                root.Add(new XAttribute("Message", message));
                root.Add(new XElement("Transaction"));
                root.Add(new XAttribute("ID", transID));
                root.Add(new XAttribute("Details", details));

                xmlDoc.Element("Batch").Add(root);
                xmlDoc.Save(myXMLLog);

So now I'm expecting the XML file to look something like this:

<!--This log was created by the Application.-->
<Batch Date="1/22/2014 10:01:11 PM" ID="166bf0d2-3bd4-4353-b309-20b6d0d59a93">
<Step>
   <Name>Start Batch</Name>
   <Success>1</Success>
   <Message>Processing Batch</Message>
<Transaction>
   <ID>N/A</ID>
   <Details>N/A</Details>
</Transaction>
</Step>
</Batch>
<Batch Date="1/22/2014 10:20:00 PM" ID="166bf0d2-3bd4-4353-b309-20b6d0d5aaa">
<Step>
   <Name>Start Batch</Name>
   <Success>1</Success>
   <Message>Processing Batch</Message>
<Transaction>
   <ID>N/A</ID>
   <Details>N/A</Details>
</Transaction>
</Step>
</Batch>

But instead I get an exception "Duplicate Attribute".

What am I doing wrong?

Thanks!

EDIT:

The XML Document does has at the top of it. Valid XML would be very nice, but not a most.

EDIT EDIT:

This is how my code looks now:

            if (File.Exists(myXMLLog))
            {              
                XDocument xmlDoc = XDocument.Load(myXMLLog);
                XElement root = new XElement("Batch",
                    new XAttribute("ID", BatchID),
                    new XAttribute("Date", now),
                    new XElement("Step",
                        new XElement("Name", step),
                        new XElement("Success", success),
                        new XElement("Message", message),
                        new XElement("Transaction",
                            new XAttribute("IDTrans", transID),
                            new XAttribute("Details", details))));
                xmlDoc.Root.Add(root);
                xmlDoc.Save(myXMLLog);
            }
            else
            {
                using (XmlWriter writer = XmlWriter.Create(myXMLLog, settings))
                {
                    writer.WriteStartDocument();

                    writer.WriteComment("This log was created by the Application.");
                    writer.WriteStartElement("Batch");
                    writer.WriteAttributeString("ID", BatchID);
                    writer.WriteAttributeString("Date", now);
                    writer.WriteStartElement("Step");
                    writer.WriteElementString("Name", step);
                    writer.WriteElementString("Success", success);
                    writer.WriteElementString("Message", message);
                    writer.WriteStartElement("Transaction");
                    writer.WriteElementString("IDTrans", transID);
                    writer.WriteElementString("Details", details);

                    writer.WriteEndElement();
                    writer.WriteEndDocument();
                }
            }

I'm ok with the format of the XML, my problem now is that is doing the BATCH inside the first BATCH

<Batch Date="1/22/2014 11:49:17 PM" ID="6966578b-b326-4f16-a315-1b4228a9fa42">
<Step><Name>Create DataTable</Name>
<Success>1</Success>
<Message>DataTable was Created and Populated</Message>
<Transaction>
<IDTrans>N/A</IDTrans>
<Details>0</Details>
</Transaction>
</Step>
<Batch Date="1/22/2014 11:49:17 PM" ID="6966578b-b326-4f16-a315-1b4228a9fa42">
<Step>
<Name>Send Email</Name>
<Success>1</Success>
<Message>Template Seleted and Filled</Message>
<Transaction Details="Email To: email@email.com Link:  " IDTrans="243b0a3c-d8b7-49c3-b1d0-asdfsdsdfsdf"/>
</Step>
</Batch>.....

EDIT FINAL

Working Code, combination of all answers:

            if (File.Exists(myXMLLog))
            {              
                XDocument xmlDoc = XDocument.Load(myXMLLog);
                XElement root = new XElement("Batch",
                    new XAttribute("ID", BatchID),
                    new XAttribute("Date", now),
                    new XElement("Step",
                        new XElement("Name", step),
                        new XElement("Success", success),
                        new XElement("Message", message),
                        new XElement("Transaction",
                            new XAttribute("IDTrans", transID),
                            new XAttribute("Details", details))));
                xmlDoc.Root.Add(root);
                xmlDoc.Save(myXMLLog);
            }
            else
            {
                using (XmlWriter writer = XmlWriter.Create(myXMLLog, settings))
                {
                    writer.WriteStartDocument();
                    writer.WriteComment("This log was created by the Application.");
                    writer.WriteStartElement("Root");
                    writer.WriteStartElement("Batch");
                    writer.WriteAttributeString("ID", BatchID);
                    writer.WriteAttributeString("Date", now);
                    writer.WriteStartElement("Step");
                    writer.WriteElementString("Name", step);
                    writer.WriteElementString("Success", success);
                    writer.WriteElementString("Message", message);
                    writer.WriteStartElement("Transaction");
                    writer.WriteElementString("IDTrans", transID);
                    writer.WriteElementString("Details", details);
                    writer.WriteEndElement();
                    writer.Flush();
                    writer.WriteEndDocument();
                }
            }

I'm happy with the results. If anyone has suggestions on how to better format the XML, please do so. Thanks everyone.


Solution

  • Your current code adds all these elements and attributes to root, instead of adding some attributes to newly created elements.

    Element creation should look like that:

    XElement root = new XElement("Batch",
        new XAttribute("ID", BatchID),
        new XAttribute("Date", now),
        new XElement("Step",
            new XElement("Name", step),
            new XElement("Success", success),
            new XElement("Message", message),
            new XElement("Transaction",
                new XElement("ID", transID),
                new XElement("Details", details))));