Thread: XML string to dataset/datagrid?

  1. #1
    Registered User
    Join Date
    Mar 2005
    Posts
    37

    XML string to dataset/datagrid?

    I currently have a C# app that makes a socket connection to a system, sends an XML stream, then the target system responds back with an XML stream which I have read into a string. I currently have it set to display this into a multi-line textbox and i can see the entire XML file. I've been able to read in select nodes from the string and set textlabels to display each portion.

    I'd like to change it so instead of a label (which is a pain to create and not automatic) it reads the XML Element that starts with "OutqEntry" into a dataset or datagrid (not sure which to use). But i'd like to have say 8 rows wide, and however many columns high from the XML.

    This is what the XML stream looks like: (i've trimmed it down a bit to fit in the window)

    Code:
    <?xml version="1.0" encoding="utf-8" ?>
    <!-- FileName: iSeries_SpecificOutq_Reply.xml -->
    <DRV>
    <CommObject Type="Reply" Data="_SpecificOutq">
    <SpecificOutq OutqName="SFOUTQ" OutqLib="DRVSFLEX">
    <OutqEntry PrintFile="QSYSPRT" SplFileNbr="1" Formtype="TESTASCII" UserData="" NbrPages="1"  Copies="1"/>
    <OutqEntry PrintFile="PRT0001" SplFileNbr="2" Formtype="CONBALANCE" UserData="" NbrPages="2" Copies="1"/>
    </SpecificOutq>
    </CommObject>
    </DRV>
    And now the messy part. This is how I'm reading the nodes in and setting the labels:

    Code:
                    XmlDocument doc = new XmlDocument();
                    doc.Load(new StringReader(s));
                    XmlNodeList splfname = doc.SelectNodes("/DRV/CommObject/SpecificOutq/OutqEntry/@PrintFile");
                    XmlNodeList frmtypename = doc.SelectNodes("/DRV/CommObject/SpecificOutq/OutqEntry/@Formtype");
                    XmlNodeList userdataname = doc.SelectNodes("/DRV/CommObject/SpecificOutq/OutqEntry/@UserData"); 
                    XmlNodeList cpysname = doc.SelectNodes("/DRV/CommObject/SpecificOutq/OutqEntry/@Copies");
                    XmlNodeList pagesname = doc.SelectNodes("/DRV/CommObject/SpecificOutq/OutqEntry/@NbrPages");
                    XmlNodeList outqname = doc.SelectNodes("/DRV/CommObject/SpecificOutq/@OutqName");
                    XmlNodeList libraryname = doc.SelectNodes("/DRV/CommObject/SpecificOutq/@OutqLib");
    
                    try
                    {
                        splf.Text = splfname[0].InnerText;
                        outq.Text = outqname[0].InnerText;
                        library.Text = libraryname[0].InnerText;
                        userdata.Text = userdataname[0].InnerText;
                        pages.Text = pagesname[0].InnerText;
                        cpys.Text = cpysname[0].InnerText;
                        frmtype.Text = frmtypename[0].InnerText;
                    }
    Attachment 9664

    I end up with this, which looks good, but requires me to make 7 labels for each line, and if i wanted to display 50 things, thats a bunch of labels to create plus I can't use the data once its displayed. So something like a dataset or grid view would be nice but I just don't know how to take what I have and make the next step. I also have the program writing the stream to an XML file as well (thats the first code block above) so i could just re-read it in instead of trying to deal with the stream if thats easier.

    Any ideas, direction or help would be greatly appreciated.

  2. #2
    eh ya hoser, got a beer? stumon's Avatar
    Join Date
    Feb 2003
    Posts
    323
    A DataGrid bound to a DataTable would probably be best if you want to break down the elements into table format, using columns and rows. By the way, you had columns and rows backwards. Number of columns is the width and number of rows is the height. This way you set up your column names by each element and just add a rows (as many as you want) with each line from the xml file. Here is some code that i used to create a DataTable and bind it to a datagrid. This took information from a database though, not an xml file.

    There are some class data members that arent shown, such as dbCommand, and dbConn, and the dbReader are all class scope, but you shouldn't need those to get the idea.

    golfRoundDG is the DataGrid i used to display the player's round information.

    Code:
          private void UpdatePlayerRounds()
          {
             DataTable playerRoundsTable = new DataTable();
             DataRow roundRow;
    
             try
             {
                // Set the query command string.
                cmdString = "Select * From roundOfGolfTable " +
                            "WHERE [playerName] = '" +
                            golferNameComboBox.Text + "'";
    
                dbCommand.CommandText = cmdString;
                dbCommand.Connection = dbConn;
    
                // Execute the Command string.
                dbReader = dbCommand.ExecuteReader();
    
                // Read each column name and add to the DataTable.
                for (int tmp = 0; tmp < dbReader.FieldCount; tmp++)
                {
                   playerRoundsTable.Columns.Add(dbReader.GetName(tmp));
                }
    
                // Read each row from the query and add each row to the DataTable.
                while (dbReader.Read())
                {
                   roundRow = playerRoundsTable.NewRow();
    
                   for (int tmp2 = 0; tmp2 < dbReader.FieldCount; tmp2++)
                   {
                      // If roundDate column is being added, format string to short date.
                      if (dbReader.GetName(tmp2) == "roundDate")
                      {
                         roundRow[dbReader.GetName(tmp2)] =
                               dbReader.GetDateTime(tmp2).ToShortDateString();
                      }
                      else
                      {
                         roundRow[dbReader.GetName(tmp2)] = dbReader.GetValue(tmp2);
                      }
                   }
                   playerRoundsTable.Rows.Add(roundRow);
                }
    
                dbReader.Close();
    
                // Associate the datagrid to the DataTable and display only 3 columns.
                golfRoundDG.AutoGenerateColumns = false;
                golfRoundDG.DataSource = playerRoundsTable;
                scoreCol.DataPropertyName = "roundScore";
                courseCol.DataPropertyName = "courseName";
                dateCol.DataPropertyName = "roundDate";
             }
             catch (Exception exc)
             {
                MessageBox.Show(exc.Message);
             }
          }
    The keyboard is the standard device used to cause computer errors!

  3. #3
    eh ya hoser, got a beer? stumon's Avatar
    Join Date
    Feb 2003
    Posts
    323
    Here is a quicky example on how to use the information once its bound to the DataGrid.

    Code:
          private void calcHandicapBtn_Click(object sender, EventArgs e)
          {
             DataRowView selectedRound;
             DataRowView selectedPlayer;
             DataRow selectedCourse;
             double finalHandicap;
    
             try
             {
                if (golfRoundDG.RowCount != 0)
                {
                   // Gets the selected player's data.
                   selectedPlayer = (DataRowView)golferNameComboBox.SelectedItem;
    
                   double[] diffArray = new double[golfRoundDG.RowCount];
    
                   for (int index = 0; index < golfRoundDG.RowCount; index++)
                   {
                      DataTable courseInfoTable = new DataTable();
                      DataRow courseRow;
    
                      // Gets the next round's data.
                      selectedRound = (DataRowView)golfRoundDG.Rows[index].DataBoundItem;
    
                      // Set the query command string.
                      cmdString = "Select * From courseTable " +
                                  "WHERE [courseName] = '" +
                                  selectedRound["courseName"].ToString() + "';";
                      dbCommand.CommandText = cmdString;
                      dbCommand.Connection = dbConn;
    
                      // Execute the command string.
                      dbReader = dbCommand.ExecuteReader();
    
                      // Read each column name and add to the DataTable.
                      for (int tmp = 0; tmp < dbReader.FieldCount; tmp++)
                      {
                         courseInfoTable.Columns.Add(dbReader.GetName(tmp));
                      }
    
                      // Read the row from the query.
                      dbReader.Read();
    
                      courseRow = courseInfoTable.NewRow();
    
                      for (int tmp2 = 0; tmp2 < dbReader.FieldCount; tmp2++)
                      {
                         courseRow[dbReader.GetName(tmp2)] = dbReader.GetValue(tmp2);
                      }
    
                      // Add the filled row into the DataTable.
                      courseInfoTable.Rows.Add(courseRow);
                      selectedCourse = courseInfoTable.Rows[0];
    
                      dbReader.Close();
    
    
                      // Determine if player is a male or female and calculate index.
                      // Equation: (Score - Course Rating) x 113 / Slope Rating.
                      if (selectedPlayer["playerGender"].ToString() == "M")
                      {
                         diffArray[index] = (
                            ((Convert.ToDouble(selectedRound["roundScore"])
                             - Convert.ToDouble(selectedCourse["courseRating"])) * 113)
                             / Convert.ToDouble(selectedCourse["menSlope"])
                            );
                      }
                      else if (selectedPlayer["playerGender"].ToString() == "F")
                      {
                         diffArray[index] = (
                            ((Convert.ToDouble(selectedRound["roundScore"])
                             - Convert.ToDouble(selectedCourse["courseRating"])) * 113)
                             / Convert.ToDouble(selectedCourse["womenSlope"])
                            );
                      }
                   }
    
                   // Use the indexes to calculate the handicap.
                   finalHandicap = CalculateHandicapWithIndexes(diffArray);
    
                   handicapLabel.Text = finalHandicap.ToString("F1");
                }
                else
                {
                   MessageBox.Show("This player has no rounds to calculate a handicap.");
                }
             }
             catch (Exception exc)
             {
                MessageBox.Show("Could Not Calculate the Handicap.");
                MessageBox.Show(exc.Message);
             }
          }
    The keyboard is the standard device used to cause computer errors!

  4. #4
    ...and never returned. StainedBlue's Avatar
    Join Date
    Aug 2009
    Posts
    168
    Wow, what a horrible looking XML file (looks like the gobbledy-goop often generated from Microsoft applications...)

    anyways, Why don't you use Linq to XML? You could make real short work of this...

    Suppose I have the following XML file:
    Code:
    
    <?xml version="1.0" encoding="utf-8" ?>
    <Products>
    	<Product>
    		<ID>12345</ID>
    		<Name>Widget</Name>
    		<Price>12.95</Price>
    	</Product>
    	<Product>
    		<ID>09876</ID>
    		<Name>Discombobulator</Name>
    		<Price>999.95</Price>
    	</Product>
    	<Product>
    		<ID>37465</ID>
    		<Name>Super Juicer</Name>
    		<Price>165.00</Price>
    	</Product>
    </Products>
    I could do the following in C#:
    Code:
    
    XElement xmlProducts = XElement.Load("Path/To/Products.xml");
    
            var products =
                from product in xmlProducts.Elements("Product")
                select new
                {
                    ID = product.Element("ID").Value,
                    Name = product.Element("Name").Value,
                    Price = Convert.ToDouble(product.Element("Price").Value)
                };
    
            productsDataGrid.DataSource = products;
            productsDataGrid.DataBind();
    or using lambda syntax :
    Code:
    
    var products = xmlProducts.Elements("Product")
       .Select(p => new
        {
            ID = p.Element("ID").Value,
            Name = p.Element("Name").Value,
            Price = Convert.ToDouble(p.Element("Price").Value)
        });
    Other configuration options could be set, like how many columns to display, etc. But you get the point.

    You can also create XML documents just as easy with XElement (it's 2010, don't use XmlDocument() anymore, geez).
    Last edited by StainedBlue; 05-02-2010 at 10:03 PM.
    goto( comeFrom() );

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 8
    Last Post: 04-25-2008, 02:45 PM
  2. We Got _DEBUG Errors
    By Tonto in forum Windows Programming
    Replies: 5
    Last Post: 12-22-2006, 05:45 PM
  3. Something is wrong with this menu...
    By DarkViper in forum Windows Programming
    Replies: 2
    Last Post: 12-14-2002, 11:06 PM
  4. Classes inheretance problem...
    By NANO in forum C++ Programming
    Replies: 12
    Last Post: 12-09-2002, 03:23 PM
  5. Warnings, warnings, warnings?
    By spentdome in forum C Programming
    Replies: 25
    Last Post: 05-27-2002, 06:49 PM