Question

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.

Was it helpful?

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))));

OTHER TIPS

First you have two "ID" properties, please remove either of them:

root.Add(new XAttribute("ID", BatchID));
……………………
root.Add(new XAttribute("ID", transID));

Then you CANNOT do that because your xml lacks of a head root. I mean you should change your xml file something like this by adding a "Root" as the root head of your xml

<!--This log was created by the BaswareVendorRegistrationCA Application.-->
<Root>
  <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>
</Root>

Then do appending:

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

            root.Add(new XAttribute("ID", 1));
            root.Add(new XAttribute("Date", 2));
            root.Add(new XElement("Step"));
            root.Add(new XAttribute("Name", 3));
            root.Add(new XAttribute("Success", 4));
            root.Add(new XAttribute("Message", 5));
            root.Add(new XElement("Transaction"));
            root.Add(new XAttribute("Details", 7));

            xmlDoc.Root.Add(root);
            xmlDoc.Save("c:\\try.xml");

PS: If your xml DOESN'T have a root element, VS will tell you that's an INVALID xml:

enter image description here

You are trying to add two ID attributes to the same Batch element.

   root.Add(new XAttribute("ID", BatchID));
   root.Add(new XAttribute("ID", transID));

I guess you need an ID and Details element inside of your Transaction element so do this when you adding your Transaction element:

root.Add(new XElement("Transaction",
             new XElement("ID", transID),
             new XElement("Details",details));

Also you can do all of these in one statement:

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

Note: As MarcinJuraszek mentioned his answer you are adding all attributes directly to your root element.For example:

root.Add(new XElement("Step"));
root.Add(new XAttribute("Name", step));
root.Add(new XAttribute("Success", success));

That code doesn't add Name and Success attribute to your Step element, it adds these two attribute to your root element.To fix this you need to add these attribute to your Step element when you creating it:

XElement stepElement = new XElement("Step",
                           new XAttribute("Name", step),
                           new XAttribute("Success", success));

Then you can add this element to the root:

root.Add(stepElement);

And a final note you should use XElement to add new Elements, according to your XML document,Name,Success,Message,Id (transaction) and Details should be XElement not XAttribute.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top