Home > Enterprise >  Getting unique values from xml
Getting unique values from xml

Time:01-25

I have this kind of xml file. Root node is Sim and there are multiple "test" subnodes. Also each "test" has an instructor. Finally each instructor has own name,surname and rank values.

<Sim>
  <Test ID="1" Description="test1" Date="17/01/2023">
    <Instructor Num="1">
      <Name>instructor1</Name>
      <Surname></Surname>
      <Rank></Rank>
    </Instructor>
  </Test>
  <Test ID="2" Description="test2" Date="16/01/2023">
    <Instructor Num="22">
      <Name>instructor22</Name>
      <Surname></Surname>
      <Rank></Rank>
    </Instructor>
  </Test>
</Sim>

I want to feed the combo box with unique instructor IDS. With this code, I can get all instructor ids, but they are not unique. For example, if two tests have the same instructor, it shows 2 instructor on combobox. Also, after combobox selection, I want to store selected instructor's name, surname and rank in temporary variables. How can I solve this?

XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlNodeList insList = doc.SelectNodes("Sim/Test/Instructor");
foreach (XmlNode xn in insList)
   cBox_ins.Items.Add(xn.Attributes["Num"].Value);

CodePudding user response:

Ask the right questions. Your task is not just to get unique instructor numbers, but to save the data for future work.

Let's do that.
Сreate a model class for storing data:

public class Instructor
{
    public int Num { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public string Rank { get; set; }
}

And an auxiliary comparator class:

public class InstructorComparer : IEqualityComparer<Instructor>
{
    public bool Equals(Instructor x, Instructor y)
    {
        return x.Num == y.Num;
    }
    public int GetHashCode(Instructor obj)
    {
        return obj.Num;
    }
}

Here is a complete sample application:

public partial class Form1 : Form
{
    ComboBox _comboBox;
    List<Instructor> _instructors;

    public Form1()
    {
        //InitializeComponent();

        var set = new HashSet<Instructor>(new InstructorComparer());
        var xml = XElement.Load("test.xml");
        foreach (var node in xml.Elements("Test").Elements("Instructor"))
        {
            var instructor = new Instructor
            {
                Num = (int)node.Attribute("Num"),
                Name = node.Element("Name").Value,
                Surname = node.Element("Surname").Value,
                Rank = node.Element("Rank").Value
            };
            set.Add(instructor);
        }

        _instructors = set.ToList();

        _comboBox = new ComboBox { Parent = this, Dock = DockStyle.Left };
        _comboBox.SelectedValueChanged  = _comboBox_SelectedValueChanged;
        _comboBox.DisplayMember = nameof(Instructor.Num);
        _comboBox.DataSource = _instructors;
    }
    private void _comboBox_SelectedValueChanged(object sender, EventArgs e)
    {
        var comboBox = (ComboBox)sender;
        var instructor = (Instructor)comboBox.SelectedValue;
        Text = instructor.Name   " "   instructor.Surname   " "   instructor.Rank;
    }
}

Load data from xml file. I'm using linq to xml, but it can be done with deserialization as well.
We use an intermediate HashSet with a comparator to get distinct data.
We save the data as List in the form field so that we can access it later.
Bind data to the combobox. Specify what will be display in the combobox.

In the event, we receive the bound data from the combobox and somehow use it. I just put them in the form's Text property.

Namespaces:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;

CodePudding user response:

To select unique instructors from the xml nodes, you can do something like this:

...your code to load XML
var instructors = insList.Cast<XmlNode>().DistinctBy(x => x.Attributes["Num"].Value);

foreach (XmlNode node in instructors)
{
   cBox_ins.Items.Add(xn.Attributes["Num"].Value);
}

To solve your second problem for storing the selected instructor details, you probably want to have a lookup table that stores all the instructors, then you can retrieve an instructor by the selected Id.

CodePudding user response:

here is the implementation of Client Code

cBox_ins.Items.AddRange(doc.SelectNodes("Sim/Test/Instructor")
        .OfType<XmlNode>().Select(x => x.Attributes["Num"].Value)
        .Distinct().ToArray());
  • Related