简体   繁体   中英

C# : select multiple nodes from XML string

With the code below I am trying to show XML nodes in a DataGridView. The first row should contain red and blue, the second row should contain green and yellow.

string xml = "<?xml version="1.0" encoding="utf-8"?>
<colors>
<color type="string">red</color>
<color type="string">blue</color>
</colors>
<colors>
<color type="string">green</color>
<color type="string">yellow</color>
</colors>
";

StringReader reader = new StringReader(xml);
XDocument doc = XDocument.Load(reader);

var res = doc.Descendants("colors").Select(n => new { n.Element("color").Value }).ToList());

dataGridView.DataSource = res;

It only shows the first value:

| red |
| green |

How do I select both color values as a result for the datagridview:

Result

| red | blue |
| green | yellow |

To begin with, your xml doesn't look to be well formed. Assuming that to be typo, you could use

var result = doc.Descendants("colors")
                .Select(x=>x.Elements("color").Select(c=>c.Value));

Output

在此处输入图片说明

If you want the result the way you show it, you'll have to do a bit more work, just having the linq expression work isn't enough

First. change your link query like this:

var result = doc.Descendants("colors")
                .SelectMany((x) => x.Elements("color").Select((c, i) => new { Id = i, Color = c.Value }));

We add an index to our result class so we can use it later for mapping the color to their own column.

Next you'll want to transform your data otherwise all colors will go in one column, as each property is mapped to a column:

I've added a few comments in the below code that explains what it does.


// create a new DataTable for mapping the transformed data
var table = new DataTable();

// loop through all items to create a column for each index.
foreach (var item in result)
{
    var colName = item.Id.ToString();
    if (!table.Columns.Contains(colName))
    {
        table.Columns.Add(colName);
    }
}

// loop again through the results to add each item to the right position in the datatable
foreach (var item in result)
{
    var isMapped = false;

// a second foreach to check if it should go into an existing row
    foreach (DataRow dataRow in table.Rows)
    {
        if (dataRow[item.Id.ToString()].ToString() == "")
        {
            dataRow[item.Id.ToString()] = item.Color;
            isMapped = true; // set to true so we don't map it again later
            break; // no need to continue the loop, we found where the color belongs
        }
    }
    if (!isMapped)
    {
        var row = table.NewRow(); // it doesn't belong in an existing row
        row[item.Id.ToString()] = item.Color;
        table.Rows.Add(row);
    }
}

// Assign the new table to your view
dataGridView1.DataSource = table;

That should do it. Keep in mind that for large sets of data these loops could become slow. There is probably a more optimal solution, but it get's the job done, you should now have data that looks like this:

| red | blue |
| green | yellow |

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM