5.4. LINQ to XML
From its beginnings, LINQ was designed to manipulate XML data as easily as it manipulates relational data. LINQ to XML represents a new API for XML-based development, equivalent in power to
XPath
and
XQuery
yet far simpler for most developers to use.
For example, let's assume the data source for our hospital scheduling application is an XML document stored in the file
SchedulingDocs.xml
. Here's the basic structure of the document:
<?xml version="1.0" standalone="yes"?>
<SchedulingDocs>
<Calls>
<Call>
<Initials>mbl</Initials>
<DateOfCall>2006-10-01T00:00:00-05:00</DateOfCall>
</Call>
.
.
.
</Calls>
<Doctors>
<Doctor>
<Initials>ay</Initials>
<GivenFirstName>Amy</GivenFirstName>
<FamilyLastName>Yang</FamilyLastName>
<PagerNumber>53300</PagerNumber>
<EmailAddress>ayang@uhospital.edu</EmailAddress>
<StreetAddress>1400 Ridge Ave.</StreetAddress>
<City>Evanston</City>
</Doctor>
.
.
.
</Doctors>
<Vacations>
<Vacation>
<Initials>jl</Initials>
<DateOfDayOff>2006-10-03T00:00:00-05:00</DateOfDayOff>
</Vacation>
.
.
.
</Vacations>
</SchedulingDocs>
Using LINQ, we load this document as
follows
:
import System.Xml.XLinq; // LINQ to XML
XElement root, calls, doctors, vacations;
root
=
XElement.Load
("SchedulingDocs.xml");
calls
= root.Element("Calls");
doctors
= root.Element("Doctors");
vacations
= root.Element("Vacations");
We now have access to the three main elements of the XML document:
calls
,
doctors
, and
vacations
. To select all the doctors, it's a simple query expression:
var
docs
= from doc in doctors.Elements()
select doc;
And to find just those doctors living in Chicago:
var
chicago
= from doc in doctors.Elements()
where doc.Element("City").Value == "Chicago"
orderby doc.Element("Initials").Value
select doc;
As you can see, querying XML documents with LINQ is conceptually the same as that of relational databases, DataSets, and other objects. The difference is that the structure of the XML document must be taken into account, e.g., in this case the document's hierarchical design and its use of elements over attributes.
An important aspect of LINQ is the ability to easily transform data into other formats. In the world of XML, transformation is commonplace given the need to create XML documents as well as translate from one schema to another. For example, suppose we need to produce a new XML document containing just the
names
of the doctors, with their initials as an attribute:
<?xml version="1.0" standalone="yes"?>
<Doctors>
<Doctor Initials="bb">Boswell, Bryan</Doctor>
<Doctor Initials="lg">Goldstein, Luther</Doctor>
.
.
.
</Doctors>
This document is easily produced by the following query, which simply projects new
XElements
:
var
docs
= from doc in doctors.Elements()
orderby doc.Element("FamilyLastName").Value,
doc.Element("GivenFirstName").Value
select new XElement("Doctor",
new XAttribute("Initials", doc.Element("Initials").Value),
doc.Element("FamilyLastName").Value +
", " +
doc.Element("GivenFirstName").Value)
;
XElement
newroot
=
new XElement("Doctors", docs)
;
The last statement creates the root element
<Doctors>
, using the query to generate the
<Doctor>
sub-elements.
Finally, here's a real-world example of translating a text-based IIS logfile into an XML document. This example comes from a series of posts to the MSDN LINQ Project General Forum, "Transforming a TXT file into XML with LINQ to XML," http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=574140&SiteID=1. The logfile contains 0 or more lines of the form:
Time IP-address Method URI Status
For example:
#Software: Microsoft Internet Information Services 5.1
#Version: 1.0
#Date: 2006-06-23 12:37:18
#Fields: time c-ip cs-method cs-uri-stem sc-status
12:37:18 127.0.0.1 GET /cobrabca 404
12:37:25 127.0.0.1 GET /cobranca 401
.
.
.
Here's the LINQ query to produce an XML document from such a log:
var
logIIS
= new XElement("LogIIS",
from line in File.ReadAllLines("file.log")
where !line.StartsWith("#")
let items = line.Split(' ')
select new XElement("Entry",
new XElement("Time", items[0]),
new XElement("IP", items[1]),
new XElement("Url", items[3]),
new XElement("Status", items[4])
)
);
LINQ over a text file? The
next
section will discuss this, and other examples, in more detail.
NOTE
The general focus of this Short Cut precludes an
in-depth
treatment of LINQ to XML. For more details, we
encourage
you to read the forthcoming Part 3 of this Short Cut series (expected Q4 2006), which focuses exclusively on LINQ to XML. Watch for an announcement at http://oreilly.com
|