2
votes

I'm just learning XDocument and LINQ queries. Here's some simple XML (which doesn't look formatted exactly right in this forum in my browser, but you get the idea . . .)

<?xml version="1.0" encoding="utf-8"?>
<quiz  
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.example.com/name XMLFile2.xsd"
  title="MyQuiz1">
  <q_a>
    <q_a_num>1</q_a_num>
    <q_>Here is question 1</q_>
    <_a>Here is the answer to 1</_a>
  </q_a>

  <q_a>
    <q_a_num>2</q_a_num>
    <q_>Here is question 2</q_>
    <_a>Here is the answer to 2</_a>
  </q_a>
</quiz>

I can iterate across all elements in my XML file and display their Name, Value, and NodeType in a ListBox like this, no problem:

        XDocument doc = XDocument.Load(sPath);
        IEnumerable<XElement> elems = doc.Descendants();

        IEnumerable<XElement> elem_list = from elem in elems
                                          select elem;

        foreach (XElement element in elem_list)
        {
            String str0 = "Name = " + element.Name.ToString() + 
                          ",  Value = " + element.Value.ToString() +
                          ",  Nodetype = " + element.NodeType.ToString();
            System.Windows.Controls.Label strLabel = new System.Windows.Controls.Label();
            strLabel.Content = str0;
            listBox1.Items.Add(strLabel);
        }

...but now I want to add a "where" clause to my query so that I only select elements with a certain name (e.g., "qa") but my element list comes up empty. I tried . . .

            IEnumerable<XElement> elem_list = from elem in elems
                                        where elem.Name.ToString() == "qa"
                                        select elem;

Could someone please explain what I'm doing wrong? (and in general are there some good tips for debugging Queries?) Thanks in advance!

2

2 Answers

1
votes

The problem is that the Name property is not a string, it's an XName. When you ToString it, you get a lot more than you think.

While it's possible to write the query in the way you're attempting to, also consider these possibilites:

//from nodes immediately below this one
IEnumerable<XElement> elem_list = doc.Elements("qa");

//from nodes of all levels below this node.
IEnumerable<XElement> elem_list = doc.Descendants("qa");
0
votes

I would perhaps change your query to something that looks more like this

var query = from q_a in document.Descendants("q_a")
            select new
            {
                Number = (int)q_a.Element("q_a_num"),
                Question = (string)q_a.Element("q_"),
                Answer = (string)q_a.Element("_a")
            };

With this, you'll pull from each of your q_a descendants the inner elements into an IEnumerable<[Anonymous Type]>, each object containing the number, question, and answer.

However, if you just want to extract the XElements where the name is q_a, you could do this using a where clause.

IEnumerable<XElement> elem_list = elems.Where(elem => elem.Name.LocalName == "q_a");

Of course, as David B showed, the where clause is not necessary here.

IEnumerable<XElement> elem_list = elems.Elements("q_a");