Search code examples
c#xmllinq-to-xmlxelement

XML in foreach loop from dataset in C#


I have to create a very specific shape XML file dynamically within C# to power a flash object on a website. The problem I have faced with many of my attempts is that most output wants each node to have some way of unique identification, I do not want that. Rather the below is the output I am going after, not the output I currently can get. Note it is also invalid XML.

<data>
    <Annual Enrollment>
        <row>
            <column>value1</column>
            <column>value2</column>
            <column>value3</column>
        </row>
        <row>
            <column>value1</column>
            <column>value2</column>
            <column>value3</column>
        </row>
    </Annual Enrollment>
    <Pre-College>
        <row>
            <column>value1</column>
            <column>value2</column>
            <column>value3</column>
        </row>
        <row>
            <column>value1</column>
            <column>value2</column>
            <column>value3</column>
        </row>
    </Pre-College>

....AND so forth. The node titles or and cannot change, nor can the roots for each tree.

The code I have so far looks like this, in my head it seems like it should work, however it does not.

  var tableResult = DashboardData.GetMetricData(1);
  // Outlinining structure
  XDocument document = new XDocument(
       new XDeclaration("1.0", "utf-8", null),
       new XElement("data",
            new XElement("AnnualEnrollment"),
            new XElement("Pre-College"),
            new XElement("Summary")
            ));
  // Now I need to append children to each of the three nodes within the root "data"
  foreach (DataRow row in tableResult.Tables[0].Rows)
  {
      document.Element("AnnualEnrollment").Add(new XElement("row"));

      foreach (var item in row.ItemArray)
      {
          var element = new XElement("column", item);


      }
  }

Solution

  • Sample below reads rows from first table and converts them to row elements, providing as content columns values converted to column elements.

    XDocument document = new XDocument(
        new XDeclaration("1.0", "utf-8", null),
        new XElement("data",
            new XElement("AnnualEnrollment", 
                from row in tableResult.Tables[0].AsEnumerable()
                select new XElement("row", 
                    from column in tableResult.Tables[0].Columns.Cast<DataColumn>()
                    select new XElement("column", row[column]))),
            new XElement("Pre-College"), // same for pre-college table
            new XElement("Summary") // and same for summary
            ));
    

    Also I'd extracted DataTable conversion into separate (extension) method:

    public static object ToXml(this DataTable dataTable)
    {
        return from row in dataTable.AsEnumerable()
               select new XElement("row",
                          from column in dataTable.Columns.Cast<DataColumn>()
                          select new XElement("column", row[column]));
    }
    

    Now your Xml generation will look like:

    XDocument document = new XDocument(
        new XDeclaration("1.0", "utf-8", null),
        new XElement("data",
            new XElement("AnnualEnrollment", tableResult.Tables[0].ToXml()),
            new XElement("Pre-College", tableResult.Tables[1].ToXml()),
            new XElement("Summary", tableResult.Tables[2].ToXml()) 
            ));