Ok. So in the following section from my XML document, I have two attributes in the Unit tag. The first, type, and the second uname. I wish to click, say a button that says "Troop" on it, and the program will search through the XML file and find the entries that are of element "Unit" and type="Troop", then output just the uname into a dataGridView. In this instance it would output just "No Light".

Right now I have the button set to just display all attributes from all entries in the file into the dataGridView. The link is an example of the output.

I just have no idea how to have it search for an attribute, or how to output just one. The rest, likely an "if" statement, makes decent sense to me.

Thank you so much for any help you can offer.

http://i246.photobucket.com/albums/gg83/templersstorms/LM_v005.jpg

<Unit type="Troop" uname="No Light">
 	<Name>No Light</Name>
	<Points>15</Points>
	<WS>3</WS>
	<BS>3</BS>
	<S>2</S>
	<T>3</T>
	<W>1</W>
	<I>4</I>
	<A>1</A>
	<Ld>9</Ld>
	<Sv>5+*</Sv>
   </Unit>

And here is the program code for the Troop Button.

private void button3_Click(object sender, EventArgs e)
               {

                   dataGridView1.DataSource = null;
                   
                   XmlDataDocument xmldataTroop = new XmlDataDocument();
                   xmldataTroop.DataSet.ReadXml(textBox1.Text);
                   DataSet dsTroop = new DataSet("Troops");
                   dsTroop = xmldataTroop.DataSet;
                   dataGridView1.DataSource = dsTroop.DefaultViewManager;
                   dataGridView1.DataMember = "Unit";
               }

Consider Linq to XML!

Example code:

using System;
using System.Linq;
using System.Xml.Linq;

class Program
{
    static void Main(string[] args)
    {
        string xml = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
<Teams>
  <Team City=""Chicago"">
    <Name>Bulls</Name>
    <LastChampionship>1998</LastChampionship>
  </Team>
  <Team City=""Los Angeles"">
    <Name>Lakers</Name>
    <LastChampionship>2009</LastChampionship>
  </Team>
  <Team City=""Boston"">
    <Name>Celtics</Name>
    <LastChampionship>2008</LastChampionship>
  </Team>
  <Team City=""San Antonio"">
    <Name>Spurs</Name>
    <LastChampionship>2007</LastChampionship>
  </Team>
</Teams>";


        XDocument document = XDocument.Parse(xml);
        // To load an xml file, use XDocument.Load(filePath)

        var teams = from team in document.Descendants("Team")                    
                    select new
                    {
                        City = team.Attribute("City").Value, // note the use of Attribute here
                        Name = team.Element("Name").Value, // and Element here
                        LastChampionship = int.Parse(team.Element("LastChampionship").Value)
                    };

        foreach (var team in teams)
        {
            Console.WriteLine("{0} {1} - Champions in {2}", team.City, team.Name, team.LastChampionship);
        }

        Console.Read();
    }
}

To apply a filter to the XML document as you are creating your initial query, just add a where clause.

var teams = from team in document.Descendants("Team")
                    where int.Parse(team.Element("LastChampionship").Value) > 2000
                    select new
                    {
                        City = team.Attribute("City").Value,
                        Name = team.Element("Name").Value,
                        LastChampionship = int.Parse(team.Element("LastChampionship").Value)
                    };

You can also decide to load the entire file as before and filter it later.

var filteredTeams = from team in teams
                            where team.LastChampionship > 2000
                            select team;

        foreach (var team in filteredTeams)
        {
            Console.WriteLine("{0} {1} - Champions in {2}", team.City, team.Name, team.LastChampionship);
        }

Edited 6 Years Ago by apegram: n/a

Ok. So I just kind of copied and pasted your code into mine and changed words and names. I am not sure that I am doing this right, but a few strange things are happening with it. The first, is that it is saying that it does not contain a definition for"Descendants", as if I do not have the correct using at the top. These are what I have;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Data.SqlClient;
using System.Xml.Linq;

The next thing it is doing is even though I commented out the only part of this code that tells it to output to a dataGridView, it is still outputting everything to dataGridView1 like it was before, which has me baffled.

Any idea as to what I am doing wrong?

And thank you for you detailed and helpful post.

dataGridView1.DataSource = null;

                   XmlDataDocument xmldataTroop = new XmlDataDocument();
                   xmldataTroop.DataSet.ReadXml(textBox1.Text);
                  // DataSet dsTroop = new DataSet("Troops");
                  // dsTroop = xmldataTroop.DataSet;
                  // dataGridView1.DataSource = dsTroop.DefaultViewManager;
                  // dataGridView1.DataMember = "Unit";



                   var Units = from Unit in xmldataTroop.Descendants("Unit")
                               where int.Parse(Unit.Attribute("type").Value) = "Troop"
                               select new
                               {
                                   uname = Unit.Attribute("uname").Value,
                      
                               };



                   foreach (var Unit in Units)
                   {
                       Console.WriteLine("{0} {1} - Champions in {2}", Unit.uname);
                   }

                   Console.Read();

Edited 6 Years Ago by templersstorms: n/a

You're going to have to tailor the code to your specific needs, there's some more cleanup and conversion you need to do.

First, your code is working with an XmlDataDocument, whereas mine is using an XDocument. Try using the XDocument class and loading your XML from whatever the source is, be it a file or a textbox or whatever.

Second, remove the loop that sends output to the console, that's not doing anything useful for your specific program. It was just an example of showing how the query results can be used.

Next, in your Units query declaration, you've modified my where clause but you've created a datatype mismatch.

where int.Parse(Unit.Attribute("type").Value) = "Troop"

Before, I was comparing the value of my selected entity to a number, which is why I included a call to int.Parse around the entity's value. You're comparing the value to a string, so int.Parse does not apply. Remove that call from the where clause. It just needs to be the following (also fixing your equals operator)

where Unit.Attribute("type").Value == "Troop"

You're going to eventually want to pull in more values from the XML source, right? So expand the portion of the query definition where you are retrieving specific values from the XML.

To bind a query resultset to a DataGridView control, you can do something like the following (again, based on my previous code example)

private void Form1_Load(object sender, EventArgs e)
        {
            // this part is the same as before
            string xml = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
<Teams>
  <Team City=""Chicago"">
    <Name>Bulls</Name>
    <LastChampionship>1998</LastChampionship>
  </Team>
  <Team City=""Los Angeles"">
    <Name>Lakers</Name>
    <LastChampionship>2009</LastChampionship>
  </Team>
  <Team City=""Boston"">
    <Name>Celtics</Name>
    <LastChampionship>2008</LastChampionship>
  </Team>
  <Team City=""San Antonio"">
    <Name>Spurs</Name>
    <LastChampionship>2007</LastChampionship>
  </Team>
</Teams>";


            XDocument document = XDocument.Parse(xml);
            // To load an xml file, use XDocument.Load(filePath)

            var teams = from team in document.Descendants("Team")
                        select new
                        {
                            City = team.Attribute("City").Value, // note the use of Attribute here
                            Name = team.Element("Name").Value, // and Element here
                            LastChampionship = int.Parse(team.Element("LastChampionship").Value)
                        };

            var filteredTeams = from team in teams
                                where team.LastChampionship > 2000
                                select team;

            // now we are binding the output to a DataGridView control. 
            BindingSource bindingSource = new BindingSource();
            foreach (var team in filteredTeams)
                bindingSource.Add(team);

            dataGridView1.DataSource = bindingSource;

        }

You can exert a greater deal of control over how the data is displayed, but I'm using the basic settings that just autogenerates columns based on the schema of the collection and displays the results.

To assist you on this topic, I would urge you to go to MSDN and other resources and search for topics on LINQ, LINQ to XML, and anonymous types in case you do not feel you have a good understanding of what's involved.

Comments
i really need to find the time to learn LINQ :p

First of all. Thank you very much. You have been a great help in helping me understand this code better. I just started teaching myself C# a few days ago, so your explanations on top of the code advice are much appreciated.

For anyone looking to do something similar, below will be the final code that worked for me. This output just the "uname" and "type" of the entries that matched the criteria.

I am marking this as solved since all I have left to do is figure out how to make it output just the "uname" and not the "type".

Thanks again.

dataGridView1.DataSource = null;
                                  

                   XDocument document = XDocument.Load(textBox1.Text);

                   var Units = from Unit in document.Descendants("Unit")
                               
                               select new
                               {
                                   type = Unit.Attribute("type").Value,
                                   uname = Unit.Attribute("uname").Value,
                      
                               };

                   var filteredUnits = from Unit in Units
                                       where Unit.type == "Troop"
                                       select Unit;

                   
 
                   BindingSource unitType = new BindingSource();
                   foreach (var Unit in filteredUnits)
                       unitType.Add(Unit);

     
                   dataGridView1.DataSource = unitType;
This question has already been answered. Start a new discussion instead.