Using LINQ Queries over XML
We have already seen that many of the LINQ to XML methods
navigate XML content and return instances of type IEnumerable<XNode>
or IEnumerable<XElement>. Because LINQ queries
can be applied to sequences of IEnumerable<T>, we
can also use them to query XML content. In
some of the previous examples, we used LINQ queries to create new XML content
or to transform XML graphs.
Now consider a different situation: you want to create sequences of
items (objects, entities, or whatever) whose value is taken from XML content.
We can use LINQ queries over XML nodes through LINQ to XML syntax.
Listing 6-32 is an example of a LINQ
query applied to the well-known XML list of customers. It filters the list of
customer elements to extract the name element
and the city attribute of each customer located in
Italy, ordering the result by the name element value.
Listing 6-32: Using
LINQ to XML and LINQ queries to query XML content
var customersFromXml =
from c in xmlCustomers.Elements("customer")
where (String)c.Attribute("country") == "Italy"
orderby (String)c.Element("name")
select new {
Name = (String)c.Element("name"),
City = (String)c.Attribute("city") };
foreach (var customer in customersFromXml) {
Console.WriteLine(customer);
}
The result is shown in the following output block:
This result is interesting, even if it is not all that exciting. To
make these opportunities more challenging, suppose you have the same XML list
of customers and a sequence of orders defined using the following LINQ query:
You can imagine that the orders were loaded via LINQ to Entities
from a Microsoft SQL Server database. We can write a complex query that joins
XML nodes with entities to extract a sequence of new objects, as shown in
Listing 6-33.
Listing 6-33: A
LINQ query that merges LINQ to XML and LINQ to Objects
var ordersWithCustomersFromXml =
from c in xmlCustomers.Elements("customer")
join o in orders
on (String)c.Element("name") equals o.Name
orderby (String)c.Element("name")
select new {
Name = (String)c.Element("name"),
City = (String)c.Attribute("city"),
IdProduct = o.IdProduct,
Quantity = o.Quantity };
This is a new and really powerful feature of LINQ and LINQ to XML,
because we can define queries over mixed contents using a unique language and
programming environment.
If you do not like the repetition of explicit casting of XML nodes
inside the LINQ query, remember that we can use the let
clause to define a more maintainable alias, as shown in
Listing 6-34.
Listing 6-34: A
LINQ query that merges LINQ to XML and LINQ to Objects, simplified by using the
let clause
var ordersWithCustomersFromXml =
from c in xmlCustomers.Elements("customer")
let xName = (String)c.Element("name")
let xCity = (String)c.Attribute("city")
join o in orders
on xName equals o.Name
orderby xName
select new {
Name = xName,
City = xCity,
IdProduct = o.IdProduct,
Quantity = o.Quantity };
Both of the previous examples return a sequence that, when printed
to the Console window, looks like the following:
Using a LINQ query, we can also create a new XML graph,
merging XML nodes and entities.