tags:

views:

430

answers:

3

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!

A: 

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");
Anthony Pegram
+1  A: 

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");
David B
However, to get the unqualified name as a string, he can use `elem.Name.LocalName.`
Anthony Pegram
A: 
I've updated my answer to show extracting the list of elements using a where clause. However, David B's answer shows that the where clause isn't exactly necessary for what you might be trying to accomplish. But between his answer and mine, you have multiple ways to getting your data, either in XElements or anonymous types, with and without where clauses.
Anthony Pegram