Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linq to XML Simple Query

I am not getting this Linq thing. I can write complex SQL queries and have written a few xpaths. I am trying to learn Linq to XML and cannot get past my first try despite poring over every terse example I can Google.

Given XML:

<Manufacturer ManufacturerName="Acme">
 <Model ModelName="RobotOne">
  <CommandText CommandName="MoveForward">MVFW</CommandText>
  <CommandText CommandName="MoveBack">MVBK</CommandText>

Query input is "Acme", "RobotOne", "MoveBack", I want output "MVBK"

Not sure if this is the best way to construct the XML how would I do it with elements instead of attributes? There are a few manufacturers and models and lots of codes

like image 837
Phil06 Avatar asked Feb 05 '10 04:02

Phil06


2 Answers

If you are having difficulty with the whole LINQ to XML thing, I'd suggest taking a slight step back and just look at linq in general. I believe that linq is very much worth the effort and will repay you many times over--particularly as we migrate to the manycore world.

I'd suggest that you forget the XML part for a moment and just think about what linq is doing--after you get what linq is about, then it will make the specialized stuff for XML easier to grok. It helps me to think about linq with these two things in mind:

  1. It is expressing standard 'operators' (extension methods) on anything that implements the interface IEnumerable<T> In other words, linq is just a method call. Some of the methods take in code (Func), some (First()) do not.
  2. this allows you to be less concerned with the guts of how these operators give you the result, and more of just declaring your intent.

It's difficult for us imperative language folks to let go of the minute (over)specification of how to get a result. What linq is basically giving us is a way to declare we want a result without saying exactly how to get it. This is why, IMO, linq is so important to learn, for it is this exact 'decoupling' of intent from the exact 'how' that is the really cool part of linq. Basically it grafts in functional language concepts into poor old imperative C#.

A helpful learning aid for LINQ is to write the C# imperative code that would do the same thing. Do this a few times, and suddenly you will see the pattern that linq does for you. So, for example, consider a 'linq-to-object' declaration.

string[] names= new string[] { "kevin", "tristan", jen" };
var result = names.where(n => n.length() > 3);

the analog in C# for the linq query would be:

List<string> list = new List<string>();
foreach(string n in names)
{
    if (n.length > 3) list.add(n);
}

I think it is fairly easy to see in this example how linq is doing the same thing as the foreach (it is actually very close to this in the reality)--but you don't have all the fluff that is just compiler goo. There is less goo and more intent in the linq version. Another way of putting this is that linq is doing the boring boilerplate stuff for you implicitly allowing your code to just show the interesting part.

In functional speak, the where() method is a higher order function. This just means that it is a function that itself takes or returns a function. Where() takes a lambda--the interesting part of the loop. The lambda is an anonymous function in C#--so Where() takes a function, thus it is higher order. I mention this because this concept is so powerful and key to understanding linq and grants insight into how linq is actually a whole new programmatic model (functional programming) bolted into C#. Getting this 'higher-order-ness' is very helpful to understanding linq.

Working with the straight List<T> queries such as the one above, I think, is the best way to wrap your head around how linq works. Afer you find yourself feeling comfortable with the straignt L-2-O queries, then look again at the XML stuff--I think you will find they will then make more sense.

With the Reactive framework due out in .NET 4.0, we will see linq expand to not only 'pull' queries but to 'push' scenarios too. I.e: the collection will fire code when it changes. It is my belief that the concepts of functional programming (of which linq is C#'s tunnel into) are the most likely bread and butter ways we will handle concurrency and parallel problems, so it is very important to learn them--not just to make our code more concise.

like image 135
Kevin Won Avatar answered Nov 15 '22 00:11

Kevin Won


Assuming that you're using this initialization:

string xml = @"
<Manufacturer ManufacturerName='Acme'>
 <Model ModelName='RobotOne'>
  <CommandText CommandName='MoveForward'>MVFW</CommandText>
  <CommandText CommandName='MoveBack'>MVBK</CommandText>
</Model>
</Manufacturer>";

XElement topElement = XElement.Parse(xml);

You can get the result via the following LINQ query:

string commandText = topElement.Elements("Model")
    .Where(element => (string)element.Attribute("ModelName") == "RobotOne")
    .Elements("CommandText")
    .Where(element => (string)element.Attribute("CommandName") == "MoveBack")
    .Select(element => element.Value)
    .FirstOrDefault();

If this XML is nested further down, you'll need more Select/Where combinations.

like image 20
micahtan Avatar answered Nov 15 '22 00:11

micahtan