Noob LINQ - Reading, Filtering XML with XDocument
I am just learning XDocument and LINQ queries. Here's a simple XML (which doesn't look formatted exactly 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 loop through all the elements in my XML file and display their name, value and NodeType in the 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 items with a specific name (eg "qa"), but my list of items is empty. I've tried.,
IEnumerable<XElement> elem_list = from elem in elems
where elem.Name.ToString() == "qa"
select elem;
Can someone please explain what I am doing wrong? (and in general, are there any good tips for debugging queries?) Thanks in advance!
a source to share
The problem is that the Name property is not a string, it is XName . When you use ToString, you get a lot more than you think.
While it is possible to write the query the way you are trying, consider these possibilities as well:
//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");
a source to share
I would change your request to something 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")
};
In doing so, you will pull q_a
internal elements from each of your descendants into IEnumerable<[Anonymous Type]>
, each object containing a number, a question and an answer.
However, if you just want to extract the XElements where the name is q_a, you can do so using the where clause.
IEnumerable<XElement> elem_list = elems.Where(elem => elem.Name.LocalName == "q_a");
Of course, as David B has shown, the sentence is not necessary here.
IEnumerable<XElement> elem_list = elems.Elements("q_a");
a source to share