Search code examples
c#xmllinq-to-xmlxelement

Creating XML using XDocument with Object that has two Lists


I am in the process of creating an XML document using XDocument in C#. I am iterating through a collection of objects that has another collection in it. Here is an example of what I am trying to create.

<Documents>
  <Document>
     <Field_1></Field_1>
     <Field_2></Field_2>
     <Field_3></Field_3>
     <Field_4></Field_4>
     <Address>
        <Item1></Item1>
        <Item2></Item2>
     </Address>
  </Document>
</Documents>

Now using my code below I can add all of the documents and their fields using my foreach loop on the main object but I am not able to add the associated Address for each document using the second foreach loop which is inside the first foreach loop. The main problem I seem to be having is when I come across a document, say 5 documents into my collection, the second foreach loop places the address of that 5th document into the 1st's documents address block. I need it to go with the 5th's document and not the 1st.

 XDocument xmlDoc = XDocument.Load(Path.Combine(@"C:\XML_Template\", "XMLTemplate.xml"));
 XElement rootElement = xmlDoc.Element("DOCUMENTS");

        foreach (var pdf in PDFDocInfo) {
            rootElement.Add(
                new XElement("DOCUMENT",
                    new XElement("Field_1", pdf.F1),
                    new XElement("Field_2", pdf.F2),
                    new XElement("Field_3", pdf.F3),
                    new XElement("Field_4", pdf.F4),
                    ));
            foreach (var address in pdf.Address) {
                rootElement.Element("DOCUMENT").Add(
                    new XElement("Address",
                        new XElement("Item1", address.I1),
                        new XElement("Item2", address.I2));
                 }
             }

Any help is appreciated.


Solution

  • On the first iteration, you create a Document element, populate the fields, and add the Address element. On the second iteration, you add a second Document element, populate the fields, and then add an Address element to the FIRST Document element (rootElement.Element("DOCUMENT") gets the first "DOCUMENT" element).

    https://msdn.microsoft.com/en-us/library/system.xml.linq.xcontainer.element(v=vs.110).aspx

    I would instead create each new "DOCUMENT", including the Address, then add that to DOCUMENTS.

    foreach (var pdf in PDFDocInfo) {
        // create a "Document" element
        newDoc = new XElement("DOCUMENT",
            new XElement("Field_1", pdf.F1),
            new XElement("Field_2", pdf.F2),
            new XElement("Field_3", pdf.F3),
            new XElement("Field_4", pdf.F4),
        );
        // add any Address elements to newDoc
        foreach (var address in pdf.Address) {
            newDoc.Add(
                new XElement("Address",
                    new XElement("Item1", address.I1),
                    new XElement("Item2", address.I2));
            }
        }
        // add newDoc to Documents
        rootElement.Add(newDoc);
    }