question

RaymondGilbers-8810 avatar image
0 Votes"
RaymondGilbers-8810 asked RaymondGilbers-8810 commented

Read a part of XML file into a table

Hello All,

I'm able to read specific data from a XML file. But the way the file is set up and how I would like my program works I need to create (I think) something like a datatable or so. Unfortunately i'm not sure how to tackle this issue.

The XML file looks like this:


 <Root>
   <CompanyProfile>
     <CompanyName>Raymond</CompanyName>
     <SiteName>Gilbers</SiteName>
     <Imo>123654</Imo>
     <MachineTotal>2</MachineTotal>
   </CompanyProfile>
   <MachineProfile>
     <MachineName>mach1</MachineName>
     <SerialNumber>123987</SerialNumber>
     <TypeNumber>AMI500</TypeNumber>
     <Type>AC</Type>
     <NominalSpeed>3000</NominalSpeed>
     <Frequency>50</Frequency>
     <NominalPower>1500</NominalPower>
   </MachineProfile>
   <MachineProfile>
     <MachineName>Mach2</MachineName>
     <SerialNumber>987654</SerialNumber>
     <TypeNumber>AMZ500</TypeNumber>
     <Type>AC</Type>
     <NominalSpeed>1500</NominalSpeed>
     <Frequency>50</Frequency>
     <NominalPower>1700</NominalPower>
   </MachineProfile>
 </Root>

what I want is to read the machineprofile. And "connect" the machinename to a combobox. So in other words I want the combobox has the items mach 1, mach2 mach3 etc and when I selet a particular selection all specific items whith this machine will be displayed.
I'm able to read the XML that is not the issue I guess but I don't know how to tackle the next issue....do I need to make a new method or create a DataTable or so. I know how machine "Machines exsist" so I thought I create a kind of loop and place it in a method but that will not work I really think I have to place each data in a table. And the selection should have some kind of identity (e.g a number) which shows me later on all the info I want to see.

How can I do this?

 private void openToolStripMenuItem_Click(object sender, EventArgs e)     
         {
             using (OpenFileDialog ofd = new OpenFileDialog())
             {
                 ofd.Filter =  "XML File (*.xml)|*.xml";
                 ofd.Title = "Open Client Profile File";
    
                 if (ofd.ShowDialog() == DialogResult.OK)
                 {
                     //Deserialize
                     _root = HelperXml.DeserializeXMLFileToObject<XmlRoot>(ofd.FileName);
    
                     lblCompanyName.Text = _root.CompanyProfile.CompanyName;
                     lblSiteName.Text = _root.CompanyProfile.SiteName;
                     lblImo.Text = _root.CompanyProfile.Imo.ToString();
                     lblMachineTotal.Text = _root.CompanyProfile.MachineTotal.ToString();
                     lblClientNumber.Text = _root.CompanyProfile.ClientNumber.ToString();
    
    
                     //Parse machine total to a machine total number.
                     int counter = Int32.Parse(lblMachineTotal.Text);
     
                 }
             }
         }

All the previous lables I'm able to read correctly but as you can see the Mach1 till 3 I would like to make vissible with selecting a selection in a combobox:

213498-image.png



This combobox e.g. the top left one should show mach 1, mach 2 etc en selecting a particular one it should show all its relevant info. What should I do?

Maybe someone could give me some ideas.

Thanks in advance!

dotnet-csharp
image.png (4.7 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

karenpayneoregon avatar image
0 Votes"
karenpayneoregon answered

Unsure if this is what you are after. I setup a ComboBox DataSource to RootMachineProfile as a list. This means you have access to each property that can be data bound to controls. Classes were generated by Visual Studio paste special.

For the ComboBox, no need to set DisplayMember.

 public class XmlOperations
 {
     public static Root Read()
     {
         const string fileName = @"XMLFile1.xml";
         var xmlSerializer = new XmlSerializer(typeof(Root), new XmlRootAttribute { ElementName = "Root", IsNullable = true });
         using (var fs = new FileStream(fileName, FileMode.Open))
         {
             return (Root)xmlSerializer.Deserialize(fs);
                
         }
     }
 }
    
 [SerializableAttribute()]
 [System.ComponentModel.DesignerCategoryAttribute("code")]
 [XmlTypeAttribute(AnonymousType = true)]
 [XmlRootAttribute(Namespace = "", IsNullable = false)]
 public partial class Root
 {
    
     private RootCompanyProfile companyProfileField;
     private RootMachineProfile[] machineProfileField;
    
     public RootCompanyProfile CompanyProfile
     {
         get => companyProfileField;
         set => companyProfileField = value;
     }
     [XmlElementAttribute("MachineProfile")]
     public RootMachineProfile[] MachineProfile
     {
         get => machineProfileField;
         set => machineProfileField = value;
     }
    
     public override string ToString() => $"{CompanyProfile.CompanyName}";
 }
    
 /// <remarks/>
 [SerializableAttribute()]
 [System.ComponentModel.DesignerCategoryAttribute("code")]
 [XmlTypeAttribute(AnonymousType = true)]
 public partial class RootCompanyProfile
 {
    
     private string companyNameField;
     private string siteNameField;
     private uint imoField;
     private int machineTotalField;
    
     public string CompanyName
     {
         get => companyNameField;
         set => companyNameField = value;
     }
     public string SiteName
     {
         get => siteNameField;
         set => siteNameField = value;
     }
     public uint Imo
     {
         get => imoField;
         set => imoField = value;
     }
     public int MachineTotal
     {
         get => machineTotalField;
         set => machineTotalField = value;
     }
 }
    
    
 [SerializableAttribute()]
 [System.ComponentModel.DesignerCategoryAttribute("code")]
 [XmlTypeAttribute(AnonymousType = true)]
 public partial class RootMachineProfile
 {
    
     private string machineNameField;
     private uint serialNumberField;
     private string typeNumberField;
     private string typeField;
     private ushort nominalSpeedField;
     private byte frequencyField;
     private ushort nominalPowerField;
    
     public string MachineName
     {
         get => machineNameField;
         set => machineNameField = value;
     }
    
     public uint SerialNumber
     {
         get => serialNumberField;
         set => serialNumberField = value;
     }
     public string TypeNumber
     {
         get => typeNumberField;
         set => typeNumberField = value;
     }
     public string Type
     {
         get => typeField;
         set => typeField = value;
     }
     public ushort NominalSpeed
     {
         get => nominalSpeedField;
         set => nominalSpeedField = value;
     }
     public byte Frequency
     {
         get => frequencyField;
         set => frequencyField = value;
     }
     public ushort NominalPower
     {
         get => nominalPowerField;
         set => nominalPowerField = value;
     }
     public override string ToString() => MachineName;
 }


Form code

 var result = XmlOperations.Read();
 List<RootMachineProfile> dataSource = result.MachineProfile.ToList();
 comboBox1.DataSource = dataSource;


5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

RaymondGilbers-8810 avatar image
0 Votes"
RaymondGilbers-8810 answered karenpayneoregon commented

Thank you very much for the detaild answer but (with all due respect) I hate copy paste I want to learn something from it. And i do not see what you have done that is not your fault but my lack of understanding C#

You created a new Class ok.....untill that I understand but than i basically get lost but again thats probably my errror I appreciate a bit more help for the sake of learning

· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

It's called XML Deserialization which just means converting XML into a C# object in memory. Serialization is the opposite, C# object in memory to XML. This concept is well documented.

Reference docs.

XmlSerializer.Deserialize Method
XmlSerializer.Serialize Method
Examples of XML Serialization
Use Visual C# to serialize an object to XML
How to deserialize an object using XmlSerializer


1 Vote 1 ·

Understood, you need to learn about classes and what better way than to examine the following code sample. The project is properly structures, classes and models separated (models are also classes that are for containing information while in the case of classes they do work)

213489-screenshot.png

213469-figure1.png


1 Vote 1 ·
screenshot.png (5.0 KiB)
figure1.png (11.0 KiB)
RaymondGilbers-8810 avatar image
0 Votes"
RaymondGilbers-8810 answered

Thanks for all the great answers I will study the example code hat will help me

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

RaymondGilbers-8810 avatar image
0 Votes"
RaymondGilbers-8810 answered RaymondGilbers-8810 commented

I think I'm almost there but I don't understand one thing. The combobox get filled with different info as I expected and as the above example.


  //Deserialize
                     _root = HelperXml.DeserializeXMLFileToObject<XmlRoot>(ofd.FileName);
    
                     lblCompanyName.ForeColor = Color.Black;
                     lblCompanyName.Text = "Company Name: " + _root.CompanyProfile.CompanyName;
                     lblSiteName.Text ="Sitename: " + _root.CompanyProfile.SiteName;
                     lblImo.Text = "IMO: " + _root.CompanyProfile.Imo.ToString();
                     lblMachineTotal.Text = "Machine Total: " + _root.CompanyProfile.MachineTotal.ToString();
                     lblClientNumber.Text = "Clientnumber: " + _root.CompanyProfile.ClientNumber.ToString();
    
    
                     _bindingSource.DataSource = _root.MachineProfiles.ToList();
                     cmbMachineName.DataSource = _bindingSource;
                     lblPower.DataBindings.Add("Text", _bindingSource, nameof(MachineProfile.NominalPower));


This is how I have done it. I created a list of the MachineProfiles and added that to the combobox. The result is what you see in below picture I dont understand why and what I do wrong.


![![![![213740-image.png][2]][1]][1]][1]


With debugging I can see that the databinding from the list worked out well (I guess)

213791-image.png


[2]: /answers/storage/attachments/213718-image.png



So I'm a bit confused cause I think I did exactly as @karenpayneoregon suggested. Does anybody see where I go wrong?


image.png (19.6 KiB)
image.png (39.4 KiB)
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

The problem (which is done right in my code sample) is that the ComboBox has not been told what to show so it shows the type.

You did not in regards to I did exactly as @karenpayneoregon suggested. I used a class with public override string ToString() => MachineName;

1 Vote 1 ·
RaymondGilbers-8810 avatar image RaymondGilbers-8810 karenpayneoregon ·

Thanks for pointing out where I made the mistake. Offcourse I made a mistake and the code was not exactly as yours. I'll jump into the code to see in which class I have to create the public override string ToString() => MachineName; Thanks again it's much appreciated

0 Votes 0 ·
JackJJun-MSFT avatar image
0 Votes"
JackJJun-MSFT answered

@RaymondGilbers-8810 ,Welcome to Microsoft Q&A, I used a new method to show the related information in the form.

First, I used the following code to convert the xml file to the datatable by using linq to xml.

  public DataTable GetDataTable(string file)
         {
             DataTable dt = new DataTable();
             XDocument doc = XDocument.Load(file);
             dt.Columns.Add("Imo");
             dt.Columns.Add("MachineTotal");
             dt.Columns.Add("MachineName");
             dt.Columns.Add("Type");
             dt.Columns.Add("NominalSpeed");
             dt.Columns.Add("Frequency");
             dt.Columns.Add("NominalPower");
    
             string[] arr = new string[7];
    
             var result = doc.Descendants("CompanyProfile").First();
             Console.WriteLine(result.Element("Imo").Value);
             Console.WriteLine(result.Element("MachineTotal").Value);
             var dr = from n in doc.Descendants("MachineProfile")
                      select new string[]{
                      arr[0] = result.Element("Imo").Value,
                      arr[1] = result.Element("MachineTotal").Value,
                      arr[2] = n.Element("MachineName").Value,
                      arr[3] = n.Element("Type").Value,
                      arr[4] = n.Element("NominalSpeed").Value,
                      arr[5] = n.Element("Frequency").Value,
                      arr[6] = n.Element("NominalPower").Value,
    
                  };
    
             foreach (var item in dr)
             {
                 dt.Rows.Add(item[0], item[1], item[2], item[3], item[4], item[5], item[6]);
             }
             return dt;
         }

Second, we could use combobox_SelectedValueChanged event to load the related information from the selected item.

  private void MachineNamecmb_SelectedValueChanged(object sender, EventArgs e)
         {
             DataRow row = dt.Rows.Cast<DataRow>().Where(i => i.Field<string>("MachineName") == MachineNamecmb.SelectedItem.ToString()).First();
             int index = dt.Rows.IndexOf(row);
             txtImo.Text = dt.Rows[index]["Imo"].ToString();
             txtFrequency.Text = dt.Rows[index]["Frequency"].ToString();
             txtMachineTotal.Text= dt.Rows[index]["MachineTotal"].ToString(); 
             txtType.Text= dt.Rows[index]["Type"].ToString();
             txtNominalPower.Text= dt.Rows[index]["NominalPower"].ToString();
             txtSpeed.Text = dt.Rows[index]["NominalSpeed"].ToString();
    
         }


Third, Please use the following code to load the MachineName to the combobox in the button_click event.

214085-image.png


Result:

214174-1.gif



Best regards,
Jack


If the answer is the right solution, please click "Accept Answer" and upvote it.If you have extra questions about this answer, please click "Comment".

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


image.png (50.9 KiB)
1.gif (138.3 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.