a7omiton
a7omiton

Reputation: 1617

How to match elements in XML - C#

I'm using a form to display XML elements. Every time I click on a module inside a listbox I want to display its <Code> value for instance, in a label on the form. The problem I'm having is that the way I've done it is that the XML is being read all at once, and I'm not able to, or don't know how to, search inside my XML file. So I think I just need a way to search in XML to find the <Code> element.

EDIT: Here is how far I am with trying to display the <Code> element in the label when it matches the <Name> element in the listbox:

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{

    var document = XDocument.Load(workingDir + @"\ModulesList.xml");

    var code = from d in document.Descendants("Name")
               where d.Value == listBox1.SelectedItem.ToString()
               select d.Parent.Element("Code").Value;

    labelCodeNumber.Text = code.ToString();

}

But the problem is that the labelCodeNumber doesn't display the value of code, it displays some weird collections stuff instead. Also I'm not sure if I am doing the output right i.e. labelCodeNumber.Text = code.ToString();

And here is the XML:

<?xml version="1.0" encoding="utf-8" ?>
<SoftwareEngineering>
  <Module>
    <Name>Algorithms and Data Structures</Name>
    <Code>3SFE504</Code>
    <Capacity>5</Capacity>
    <Semester>1</Semester>
    <Prerequisite>none</Prerequisite>
  </Module>
  <Module>
    <Name>3D Graphics I</Name>
    <Code>3SFE508</Code>
    <Capacity>5</Capacity>
    <Semester>1</Semester>
    <Prerequisite>none</Prerequisite>
  </Module>
  <Module>
    <Name>Event-Driven Programming</Name>
    <Code>3SFE513</Code>
    <Capacity>10</Capacity>
    <Semester>1</Semester>
    <Prerequisite>none</Prerequisite>
  </Module>
  <Module>
    <Name>Object Oriented Design</Name>
    <Code>3SFE514</Code>
    <Capcity>10</Capcity>
    <Semester>1</Semester>
    <Prerequisite>none</Prerequisite>
  </Module>
  <Module>
    <Name>Requirements Engineering</Name>
    <Code>3SFE516</Code>
    <Capacity>10</Capacity>
    <Semester>1</Semester>
    <Prerequisite>none</Prerequisite>
  </Module>
  <Module>
    <Name>Introduction to AI</Name>
    <Code>3SFE599</Code>
    <Capacity>5</Capacity>
    <Semester>1</Semester>
    <Prerequisite>none</Prerequisite>
  </Module>
  <Module>
    <Name>Java Mobile Application Development</Name>
    <Code>3SFE540</Code>
    <Capacity>5</Capacity>
    <Semester>1</Semester>
    <Prerequisite>3SFE514(corequisite)</Prerequisite>
  </Module>
  <Module>
    <Name>C# .NET Programming</Name>
    <Code>3SFE541</Code>
    <Capacity>5</Capacity>
    <Semester>1</Semester>
    <Prerequisite>3SFE514(corequisite)</Prerequisite>
  </Module>
  <Module>
    <Name>Software Engineering Group Project</Name>
    <Code>3SFE515</Code>
    <Capacity>5</Capacity>
    <Semester>2</Semester>
    <Prerequisite>3SFE514(corequisite)</Prerequisite>
  </Module>
  <Module>
    <Name>Software Engineering</Name>
    <Code>3SFE519</Code>
    <Capacity>10</Capacity>
    <Semester>2</Semester>
    <Prerequisite>none</Prerequisite>
  </Module>
  <Module>
    <Name>Mobile User Interface Development</Name>
    <Code>3SFE542</Code>
    <Capacity>5</Capacity>
    <Semester>2</Semester>
    <Prerequisite>3SFE540</Prerequisite>
  </Module>
  <Module>
    <Name>Interactive Multimedia</Name>
    <Code>3MTS954</Code>
    <Capacity>5</Capacity>
    <Semester>2</Semester>
    <Prerequisite>none</Prerequisite>
  </Module>
  <Module>
    <Name>Concurrent Programming</Name>
    <Code>3SFE555</Code>
    <Capacity>5</Capacity>
    <Semester>2</Semester>
    <Prerequisite>none</Prerequisite>
  </Module>
  <Module>
    <Name>Mobile Gaming</Name>
    <Code>3SFE557</Code>
    <Capacity>10</Capacity>
    <Semester>2</Semester>
    <Prerequisite>none</Prerequisite>
  </Module>
  <Module>
    <Name>Intelligent Systems</Name>
    <Code>3SFE500</Code>
    <Capacity>10</Capacity>
    <Semester>2</Semester>
    <Prerequisite>3SFE599</Prerequisite>
  </Module>
  <Module>
    <Name>3D Graphics II</Name>
    <Code>3SFE501</Code>
    <Capacity>10</Capacity>
    <Semester>2</Semester>
    <Prerequisite>3SFE508</Prerequisite>
  </Module>
</SoftwareEngineering>

FINAL EDIT: I figured it out! Thanks to Marcin and psubsee for their help and contribution. This code below goes in the listbox1_selectedindexchanged method

var code = from d in document.Descendants("Name")
           where d.Value == (String) listBox1.SelectedItem
           select d.Parent.Element("Code").Value;

foreach (var item in code)
{
    labelCodeNumber.Text = item.ToString();
}

Upvotes: 1

Views: 2002

Answers (3)

psubsee2003
psubsee2003

Reputation: 8741

The points about using the Xml.Linq namespace are good ones because loading the data into an XDocument and querying the elements is much cleaner to look at and easier to maintain than the XmlReader code you are using. If you ever change the format of your xml data or reuse the code in another method, it will be easier to update the query vs modifying the XmlReader code you have. The only advantage to XmlReader would be if the XML is huge and you do not want to read it into memory all at once.

(But you said you wanted to be different)

The issue you are having with adding the values to the ListBox is related to the fact that ListBox.Items.AddRange() is expecting an object array and you are trying to pass IEnumerable<String>. You need to convert your IEnumerable to an array first, as in my answer to another of your questions earlier

listBox1.Items.AddRange(names.ToArray());

Upvotes: 0

MarcinJuraszek
MarcinJuraszek

Reputation: 125630

You should change your concept and use XDocument instead of XmlReader:

var document = XDocument.Load(workingDir + @"\ModulesList.xml");

To fill up the listbox use something like that:

var items = From d in document.Descendants("Name")
            select d.Value;

foreach(var item in items)
    listBox1.Items.Add(item);

And then to find <code> from selected element you can make that kind of Linq to XML query:

var code = From d in document.Descendants("Name")
           where d.Value == SelectedName
           select d.Parent.Element("Code").Value

Upvotes: 5

Henk Holterman
Henk Holterman

Reputation: 273274

If you are reading it all at once then do not use an XmlReader.

Load it into an XDocument and you can use LINQ to find whatever you want.

XDocument doc = XDocument.Load(fileName);  // do this 1x

// untested
var names = doc.Root.Descendants("Module").Elements("Name").Select(e => e.Value);
listBox1.Items.AddRange(names);

Upvotes: 5

Related Questions