views:

159

answers:

3

Updated to be clear.

Step One: I have a XML file that I want to load into a DatGridView. (Mostly working thanks to Max, but I still have a problem with the XML rollup)

Step Two: Run some code based on user input -- (not part of this solution)

Step Three: Export the DataGridView into a CSV File. (Solved by Max! Thanks Man That was exactly what I was trying to do on that part.)

Using VS 2008 C#

(Created a new project)

Sample from the XML file cars.xml

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <car>
    <year>2010</year>
    <make>Chevy</make>
    <model>Surburban</model>
    <color-e>Black</color-e>
    <color-i>Black</color-i>
    <features>
      <Engine>8 cylinder</Engine>
      <gas>Petrol</gas>
      <doors>5</doors>
      <miles>12312</miles>
    </features>
    </car>
  <car>
    <year>2001</year>
    <make>Ford</make>
    <model>Excursion</model>
    <color-e>Black</color-e>
    <color-i>Black</color-i>
    <features>
      <Engine>10 cylinder</Engine>
      <gas>Petrol</gas>
      <doors>5</doors>
      <miles>90312</miles>
    </features>
  </car>
  <car>
    <year>1999</year>
    <make>Chevy</make>
    <model>corvette</model>
    <color-e>Silver</color-e>
    <color-i>Black</color-i>
    <features>
      <Engine>8 cylinder</Engine>
      <gas>Petrol</gas>
      <doors>3</doors>
      <miles>44222</miles>
    </features>
  </car>
</root>

This is a winform application. It has two button, one textbox, and one datagridview. button one should load the XML data into the datagrid. Then button two should save the data in the datagridview to a CSV file.

Here is the code I have so far to open and load the xml into the datagridview.

namespace carsXML
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
        var cars = XDocument.Load(@"C:\cars.xml");
        var query = from c in cars.Descendants("car")
                    select new
                    {
                        Year = (string)c.Element("year").Value,
                        Make = (string)c.Element("make").Value,
                        Model = (string)c.Element("model").Value,
                        // I needed to step directly into the sub element.
                        gas = (string)c.Element("features").Element("gas").Value,
                        doors = (string)c.Element("features").Element("doors").Value,
                        miles = (string)c.Element("features").Element("miles").Value


                    };

        dataGridView1.DataSource = query.ToList();

        }

        private void button2_Click(object sender, EventArgs e)
        {
          dataGridView1.ExportToCSV(@"C:\cars-griddump.csv"); 
         //Added Class Max showed me.  This works, I have only tested it on a small
         // XML file so far but it seems to work exactly as I wanted.
        }
    }
}

This gets the elements directly below the car element. When it gets to the feature element the application crashes. (null ref etc.)

So the last part of this before I am done with this little project is to figure out the XML rollup. When the code reads the car elements it gets all of the sub elements that are directly under car. It fails when it gets to the element that has additional sub elements and does not add them to the datagridview.

//Rollup problem fixed. It took me a while though! // Thank you for all of the help!

A: 

One way is to load the XML in to a dataset and then save the dataset to a CSV. This is the easiest one. But this has some dependency the structure of the XML tree.

Update to show a sample to save DataTable to csv:

We can call this method for each DataTable in the DataSet

void SaveDTtoCSV(DataTable dt)
{
    // Save data to CSV file 
    StreamWriter writer = new StreamWriter(@"c:/dsoutput.csv");
    // First we will write the headers.
    int iColCount = dt.Columns.Count;
    for(int i = 0; i < iColCount; i++)
    {
        writer.Write(dt.Columns[i]);
        if (i < iColCount - 1)
        {
            writer.Write(",");
        }
    }
    writer.Write(writer.NewLine);
    // Now write all the rows.
    foreach (DataRow dr in dt.Rows)
    {
        for (int i = 0; i < iColCount; i++)
        {
            if (!Convert.IsDBNull(dr[i]))
            {
                writer.Write(dr[i].ToString());
            }
            if ( i < iColCount - 1)
            {
                writer.Write(",");
            }
        }
        writer.Write(writer.NewLine);
    }
    writer.Close();
}
Kangkan
ok, so to do that I would use the following code...string myXMLfile = textBox1.Text.ToString(); //this has the path and file name in it.DataSet ds = new DataSet("myXMLDataset");ds.ReadXml(myXMLfile);/*How do I process elements in the ds? Do I have to create the ds.table as well or is this done by the ReadXml?*/
Code Smack
I am not sure if there is a simple way of saving a dataset to a csv directly. But you shall have to iterate through the records in each of the DataTables in the DataSet. For clarity, I am updating my answer.
Kangkan
Thanks Kangkan, but going directly to the DataGridView works bets for the solution. Thank you though!
Code Smack
A: 
Max
OK, I think that this is on the path I would like to go, but I have some gaps...var cars = Document.Load(textBox1.Text.ToString()).Descendants("Cars"); // This is logical to me, but it is not clear to me how to map this to Linq? or a datagridview.I know how to use Linq to SQL with a SQL DB in the background, but I so not know the next step to get the car object into a Datagridview.I tried the following. Code: BindingSource carsBS = new BindingSource(); carsBS.DataSource = from cars1 in cars.Elements()select cars1; dataGridView1.DataSource = carsBS;I like this approach though.
Code Smack
Hello Max, Any idea on the element rollup? Everything I try gives me an error message. Thanks,CodeSmack
Code Smack
I got the sub element. I was thinking about it wrong. updating the code now.
Code Smack
A: 

There's not much detail in your question, but the best I can do is assume that you've got an XML file that contains information related to cars, like

<cars>
  <car>
    <make>Honda</model>
    <model>Odyssey</model>
    <year>2009</year>
  </car>
  <car>
    <make>Toyota</make>
    <model>Sienna</model>
    <year>2010</year>
  </car>
</cars>

And then you want to write a CSV that looks like this:

make   model   year
Honda  Odyssey 2009
Toyota Sienna  2010

Since you have tagged linq-to-xml, I assume you want to use LINQ, though you might not know what to do next. Try using XDocument.Load to load your XML file. You'll then use Element() and Elements() to get at the nodes in the XML structure. For example, if xml = XDocument.Load(filename), then xml.Element("cars") should give you the root node. With that, you can use xml.Element("cars").Elements() to get all of the elements... and so on and so forth.

Dave