views:

54

answers:

4

Here's the sample XML

<?xml version="1.0" encoding="utf-8" ?>
<Instructions>
  <Instruction>
    <Brand>Brand1</Brand>
    <Text>
      this is text for Brand1
    </Text>
  </Instruction>
  <Instruction>
    <Brand>Brand2</Brand>
    <Text>
      Brand2 text is slightly different
    </Text>
  </Instruction>
  <Instruction>
    <Brand>Brand3</Brand>
    <Text>
      Brand3 has boring text
    </Text>
  </Instruction>
  <Instruction>
    <Brand>Brand4</Brand>
    <Text>
      Brand4 had long text until the editor got hold of this file
    </Text>
  </Instruction>
</Instructions>

My code is this:

string WhoAmI = "Brand1";
string t =
              (from Instruction in xmlDoc.Descendants("Instruction")
               where (string)Instruction.Element("Brand").Value == WhoAmI
               select t = Instruction.Element("Text").Value
               ).ToString();

//end code

t is always

System.Linq.Enumerable+WhereSelectEnumerableIterator`2 [System.Xml.Linq.XElement,System.String]

not

this is text for Brand1

What am I doing wrong?

+2  A: 

A LINQ statement returns a sequence of values, not a single value. So calling .ToString() on a sequence object will, ordinarily, not give you anything particularly useful.

In this case, your statement is returning a sequence with one value in it, but still a sequence. So you need to write a LINQ statement that only returns one value:

string t = (from ... select ...).First();

There's other implications to consider here, such that First() will throw an exception if the sequence is empty. FirstOrDefault() will return null instead.

Rex M
But is there a way to get to the useful value wrapped in the "Text" tags?
John H.
@John H yes, that's what I am describing.
Rex M
I understand what you are saying now after reading all the replies. Thanks one million.
John H.
A: 

Try replacing ToString() with FirstOrDefault()

J Cooper
A: 

This query will return a sequence of strings not a single string. So the .ToString() method call will be the IEnumerable ToString method.

If you are confident that your query will always only return 1 string you can use the Single() or SingleOrDefault() methods to just return the string.

string WhoAmI = "Brand1"; 
string t = 
              (from Instruction in xmlDoc.Descendants("Instruction") 
               where (string)Instruction.Element("Brand").Value == WhoAmI 
               select t = Instruction.Element("Text").Value 
               ).SingleOrDefault();
Tim Jarvis
A: 

This will give you a collection of the Text nodes' contained text values. However, if either a Text node or a Brand node is missing this query will fail. What the code you posted was doing was not accepting a collection as a result; you were casting the collection object returned to a string which by default gives you just the name of the object.

You will need to loop through the list returned by the query to do something useful with the multiple values returned...

        var results = (from e in doc.Descendants("Instruction")
                       where e.Descendants("Brand").First().Value == WhoAmI
                       select e.Descendants("Text").First().Value).ToList();
Tahbaza