Thư viện tri thức trực tuyến
Kho tài liệu với 50,000+ tài liệu học thuật
© 2023 Siêu thị PDF - Kho tài liệu học thuật hàng đầu Việt Nam

Apress pro LINQ Language Integrated Query in C# 2008 phần 6 ppt
Nội dung xem thử
Mô tả chi tiết
CHAPTER 8 ■ LINQ TO XML OPERATORS 275
new XElement("BookParticipant",
new XAttribute("type", "Editor"),
new XElement("FirstName", "Ewan"),
new XElement("LastName", "Buckingham"))));
IEnumerable<XElement> elements =
xDocument.Element("BookParticipants").Descendants("FirstName");
// First, I will display the source elements.
foreach (XElement element in elements)
{
Console.WriteLine("Source element: {0} : value = {1}",
element.Name, element.Value);
}
// Now, I will display the ancestor elements for each source element.
foreach (XElement element in elements.Ancestors())
{
Console.WriteLine("Ancestor element: {0}", element.Name);
}
In the previous example, first, I create an XML document. Next, I generate a sequence of FirstName
elements. Remember, this Ancestors method is called on a sequence of nodes, not on a single node,
so I need a sequence on which to call it. Because I want to be able to display the names of the nodes
for identification purposes, I actually build a sequence of elements because elements have names
but nodes do not. I then enumerate through the sequence displaying the source elements just so you
can see the source sequence. Then, I enumerate on the elements returned from the Ancestors method
and display them. Here are the results:
Source element: FirstName : value = Joe
Source element: FirstName : value = Ewan
Ancestor element: BookParticipant
Ancestor element: BookParticipants
Ancestor element: BookParticipant
Ancestor element: BookParticipants
As you can see, it displays the two source sequence elements, the two FirstName elements. It
then displays the ancestors for each of those two elements.
So using the Ancestors operator, I am able to retrieve all of the ancestor elements for each
node in a sequence of nodes. In this case, my sequence is a sequence of elements, but that is alright
because an element is derived from a node. Remember, do not confuse the Ancestors operator
that is called on a sequence of nodes, which I just demonstrated, with the Ancestors method I
cover in the previous chapter.
Now this example is not quite as impressive as it could be because I needed to expand the code
for demonstration purposes. For example, I wanted to capture the sequence of FirstName elements,
because I wanted to display them so you could see the source elements in the output. So the statement containing the call to the Descendants method and the subsequent foreach block are for this
purpose. Then in the second foreach loop, I call the Ancestors operator and display each ancestor
element. In reality, in that second foreach loop, I could have called the Ancestors method from the
previous chapter on each element in the sequence of FirstName elements and not even called the
Ancestors operator I am demonstrating. Listing 8-2 is an example demonstrating what I could have
done, which would have accomplished the same result, but without even using the Ancestors operator.
Rattz_789-3.book Page 275 Tuesday, October 16, 2007 2:21 PM
276 CHAPTER 8 ■ LINQ TO XML OPERATORS
Listing 8-2. The Same Results as Listing 8-1 But Without Calling the Ancestors Operator
XDocument xDocument = new XDocument(
new XElement("BookParticipants",
new XElement("BookParticipant",
new XAttribute("type", "Author"),
new XElement("FirstName", "Joe"),
new XElement("LastName", "Rattz")),
new XElement("BookParticipant",
new XAttribute("type", "Editor"),
new XElement("FirstName", "Ewan"),
new XElement("LastName", "Buckingham"))));
IEnumerable<XElement> elements =
xDocument.Element("BookParticipants").Descendants("FirstName");
// First, I will display the source elements.
foreach (XElement element in elements)
{
Console.WriteLine("Source element: {0} : value = {1}",
element.Name, element.Value);
}
foreach (XElement element in elements)
{
// Call the Ancestors method on each element.
foreach(XElement e in element.Ancestors())
// Now, I will display the ancestor elements for each source element.
Console.WriteLine("Ancestor element: {0}", e.Name);
}
The difference between this example and the previous is that instead of calling the Ancestors
operator on the elements sequence in the foreach loop, I just loop on each element in the sequence
and call the Ancestors method on it. In this example, I never call the Ancestors operator; I merely call
the Ancestors method from the previous chapter. This code produces the same output though:
Source element: FirstName : value = Joe
Source element: FirstName : value = Ewan
Ancestor element: BookParticipant
Ancestor element: BookParticipants
Ancestor element: BookParticipant
Ancestor element: BookParticipants
However, thanks to the Ancestors operator and the conciseness of LINQ, this query can be
combined into a single, more concise statement as demonstrated in Listing 8-3.
Listing 8-3. A More Concise Example of Calling the First Ancestors Prototype
XDocument xDocument = new XDocument(
new XElement("BookParticipants",
new XElement("BookParticipant",
new XAttribute("type", "Author"),
new XElement("FirstName", "Joe"),
new XElement("LastName", "Rattz")),
Rattz_789-3.book Page 276 Tuesday, October 16, 2007 2:21 PM
CHAPTER 8 ■ LINQ TO XML OPERATORS 277
new XElement("BookParticipant",
new XAttribute("type", "Editor"),
new XElement("FirstName", "Ewan"),
new XElement("LastName", "Buckingham"))));
foreach (XElement element in
xDocument.Element("BookParticipants").Descendants("FirstName").Ancestors())
{
Console.WriteLine("Ancestor element: {0}", element.Name);
}
In this example, I cut right to the chase and call the Ancestors operator on the sequence of elements
returned by the Descendants method. So the Descendants method returns a sequence of elements,
and the Ancestors operator will return a sequence of elements containing all ancestors of every
element in the sequence it is called on.
Since this code is meant to be more concise, it does not display the FirstName elements as the
two previous examples did. However, the ancestor elements should be the same. Let’s verify that
they are:
Ancestor element: BookParticipant
Ancestor element: BookParticipants
Ancestor element: BookParticipant
Ancestor element: BookParticipants
And they are! In your production code, you would probably opt for a more concise query like the
one I just presented. However, in this chapter, the examples will be more verbose, like Listing 8-1, for
demonstration purposes.
To demonstrate the second Ancestors prototype, I will use the same basic code as Listing 8-1,
except I will change the call to the Ancestors operator so that it includes the parameter BookParticipant
so that I only get the elements matching that name. That code looks like Listing 8-4.
Listing 8-4. Calling the Second Ancestors Prototype
XDocument xDocument = new XDocument(
new XElement("BookParticipants",
new XElement("BookParticipant",
new XAttribute("type", "Author"),
new XElement("FirstName", "Joe"),
new XElement("LastName", "Rattz")),
new XElement("BookParticipant",
new XAttribute("type", "Editor"),
new XElement("FirstName", "Ewan"),
new XElement("LastName", "Buckingham"))));
IEnumerable<XElement> elements =
xDocument.Element("BookParticipants").Descendants("FirstName");
// First, I will display the source elements.
foreach (XElement element in elements)
{
Console.WriteLine("Source element: {0} : value = {1}",
element.Name, element.Value);
}
Rattz_789-3.book Page 277 Tuesday, October 16, 2007 2:21 PM
278 CHAPTER 8 ■ LINQ TO XML OPERATORS
// Now, I will display the ancestor elements for each source element.
foreach (XElement element in elements.Ancestors("BookParticipant"))
{
Console.WriteLine("Ancestor element: {0}", element.Name);
}
The results now should only include the BookParticipant elements and of course the source
elements, but the two BookParticipants elements that are displayed in the first prototype’s example
should now be gone:
Source element: FirstName : value = Joe
Source element: FirstName : value = Ewan
Ancestor element: BookParticipant
Ancestor element: BookParticipant
And they are.
AncestorsAndSelf
The AncestorsAndSelf operator can be called on a sequence of elements and returns a sequence
containing the ancestor elements of each source element and the source element itself. This operator is
just like the Ancestors operator except for the fact that it can only be called on elements, as opposed
to nodes, and also includes each source element in the returned sequence of ancestor elements.
Prototypes
The AncestorsAndSelf operator has two prototypes.
The First AncestorsAndSelf Prototype
public static IEnumerable<XElement> AncestorsAndSelf (
this IEnumerable<XElement> source
)
This version of the operator can be called on a sequence of elements and returns a sequence of
elements containing each source element itself and its ancestor elements.
The Second AncestorsAndSelf Prototype
public static IEnumerable<XElement> AncestorsAndSelf<T> (
this IEnumerable<XElement> source,
XName name
)
This version is like the first, except a name is passed and only those source elements and its
ancestors matching the specified name are returned in the output sequence.
Examples
For an example of the first AncestorsAndSelf prototype, I will use the same basic example I used for
the first Ancestors prototype, except I will call the AncestorsAndSelf operator instead of the Ancestors
operator, as shown in Listing 8-5.
Rattz_789-3.book Page 278 Tuesday, October 16, 2007 2:21 PM
CHAPTER 8 ■ LINQ TO XML OPERATORS 279
Listing 8-5. Calling the First AncestorsAndSelf Prototype
XDocument xDocument = new XDocument(
new XElement("BookParticipants",
new XElement("BookParticipant",
new XAttribute("type", "Author"),
new XElement("FirstName", "Joe"),
new XElement("LastName", "Rattz")),
new XElement("BookParticipant",
new XAttribute("type", "Editor"),
new XElement("FirstName", "Ewan"),
new XElement("LastName", "Buckingham"))));
IEnumerable<XElement> elements =
xDocument.Element("BookParticipants").Descendants("FirstName");
// First, I will display the source elements.
foreach (XElement element in elements)
{
Console.WriteLine("Source element: {0} : value = {1}",
element.Name, element.Value);
}
// Now, I will display the ancestor elements for each source element.
foreach (XElement element in elements.AncestorsAndSelf())
{
Console.WriteLine("Ancestor element: {0}", element.Name);
}
Just as with the first Ancestors prototype, first, I create an XML document. Next, I generate a
sequence of FirstName elements. Remember, this AncestorsAndSelf method is called on a sequence
of elements, not on a single element, so I need a sequence on which to call it. I then enumerate through
the sequence displaying the source elements just so you can see the source sequence. Then, I enumerate
on the elements returned from the AncestorsAndSelf method and display them.
If this works as I expect, the results should be the same as the results from the first Ancestors
prototype’s example, except now the FirstName elements should be included in the output. Here are
the results:
Source element: FirstName : value = Joe
Source element: FirstName : value = Ewan
Ancestor element: FirstName
Ancestor element: BookParticipant
Ancestor element: BookParticipants
Ancestor element: FirstName
Ancestor element: BookParticipant
Ancestor element: BookParticipants
For an example of the second AncestorsAndSelf prototype, I will use the same basic example
that I used in the example for the second Ancestors prototype, except, of course, I will change the call
from the Ancestors method to the AncestorsAndSelf method, as shown in Listing 8-6.
Rattz_789-3.book Page 279 Tuesday, October 16, 2007 2:21 PM