LINQ out of XML

The LINQ XML objects provide a standard assortment of LINQ functions that make moving data from those objects into IEnumerable objects simple. Using these functions, it’s about as easy to select data from the XML objects as it is from IEnumerable objects such as arrays and lists.

Because the XML objects represent special hierarchical data structures, they also provide methods to help you search those data structures. For example, the XElement object provides a Descendants function that searches the object’s descendants for elements of a certain type.

The following code extracts the x_all XElement object’s Customer descendants. It selects their FirstName and LastName attributes, and the balance saved as each element’s value.

Dim select_all = From cust In x_all.Descendants("Customer")
    Order By CDec(cust.Value)
    Select FName = cust.Attribute("FirstName").Value,
           LName = cust.Attribute("LastName").Value,
           Balance = cust.Value

The program can now loop through the select_all object just as it can loop through any other IEnumerable selected by a LINQ query.

The following query selects only customers with a negative balance:

Dim x_neg = From cust In x_all.Descendants("Customer")
    Where CDec(cust.Value) < 0
    Select FName = cust.Attribute("FirstName").Value,
           LName = cust.Attribute("LastName").Value,
           Balance = cust.Value

Example program LinqToXml, which is available for download on the book’s website, demonstrates these XML literals containing holes.

The following table describes other methods supported by XElement that a program can use to navigate through an XML hierarchy. Most of the functions return IEnumerable objects that you can then use in LINQ queries.

FUNCTION RETURNS
Ancestors IEnumerable containing all ancestors of the element.
AncestorsAndSelf IEnumerable containing this element followed by all of its ancestors.
Attribute The element’s attribute with a specific name.
Attributes IEnumerable containing the element’s attributes.
Descendants IEnumerable containing all descendants of the element.
DescendantsAndSelf IEnumerable containing this element followed by all of its descendants.
DescendantNodes IEnumerable containing all descendant nodes of the element. These include all nodes such as XElement and XText.
DescendantNodesAndSelf IEnumerable containing this element followed by all of its descendant nodes.
Element The first child element with a specific name.
Elements IEnumerable containing the immediate children of the element.
ElementsAfterSelf IEnumerable containing the siblings of the element that come after this element.
ElementsBeforeSelf IEnumerable containing the siblings of the element that come before this element.
Nodes IEnumerable containing the nodes that are immediate children of the element. These include all nodes such as XElement and XText.
NodesAfterSelf IEnumerable containing the sibling nodes of the element that come after this element.
NodesBeforeSelf IEnumerable containing the sibling nodes of the element that come before this element.

Most of these functions that return an IEnumerable take an optional parameter that you can use to indicate the names of the elements to select. For example, if you pass the Descendants function the parameter “Customer,” the function returns only the descendants of the element that are named Customer.

Example program LinqToXmlFunctions, which is available for download on the book’s website, demonstrates these XML functions.

In addition to these functions, Visual Basic’s LINQ query syntax recognizes several axis selectors. In XML, an axis is a “direction” in which you can move from a particular node. These include such directions as the node’s descendants, the node’s immediate children, and the node’s attributes.

The following table gives examples of shorthand expressions for node axes and their functional equivalents.

SHORTHAND MEANING EQUIVALENT
x...<Customer> Descendants named Customer x.Descendants(“Customer”)
x.<Child> An element named Child that is a child of this node x.Element(“Child”)
x.@<FirstName> The value of the FirstName attribute x.Attribute(“FirstName”).Value
x.@FirstName The value of the FirstName attribute x.Attribute(“FirstName”).Value

For example, consider the following XElement literal:

Dim x_all As XElement =
    <AllCustomers>
        <PositiveBalances>
            <Customer FirstName="Dan" LastName="Dump">117.95</Customer>
            <Customer FirstName="Ann" LastName="Archer">100.00</Customer>
            <Customer FirstName="Carly" LastName="Cant">62.40</Customer>
        </PositiveBalances>
        <NegativeBalances>
            <Customer FirstName="Ben" LastName="Best">-24.54</Customer>
            <Customer FirstName="Frank" LastName="Fix">-150.90</Customer>
            <Customer FirstName="Edna" LastName="Ever">-192.75</Customer>
        </NegativeBalances>
    </AllCustomers>

The following code uses axis shorthand to make several different selections:

' Select all Customer descendants of x_all.
Dim desc = x_all.Descendants("Customer") ' Functional version.
Dim desc2 = x_all.<Customer>             ' LINQ query version.
 
' Select Customer descendants of x_all where FirstName attribute is Ben.
Dim ben = From cust In x_all.Descendants("Customer")
    Where cust.@FirstName = "Ben"
 
' Select Customer descendants of x_all where FirstName attribute is Ann.
Dim ann = From cust In x_all.<Customer>
    Where cust.@<FirstName> = "Ann"
 
' Starting at x_all, go to the NegativeBalances node and find
' its descendants that are Customer elements. Select those with
' value less than -50.
Dim neg_desc2 = From cust In x_all.<NegativeBalances>...<Customer>
    Where CDec(cust.Value) < -50

Example program LinqAxes, which is available for download on the book’s website, demonstrates these LINQ query XML axes.

Note that IEnumerable objects allow indexing so you can use an index to select a particular item from the results of any of these functions that returns an IEnumerable. For example, the following statement starts at element x_all, goes to descendants named NegativeBalances, gets that element’s Customer children, and then selects the second of them (indexes are numbered starting with zero):

Dim neg_cust1 = x_all.<NegativeBalances>.<Customer>(1)

Together the LINQ XML functions and query axes operators let you explore XML hierarchies quite effectively.

In addition to all of these navigational features, the LINQ XML classes provide the usual assortment of methods for manipulating XML hierarchies. Those functions let you find an element’s parent, add and remove elements, and so forth. For more information, see the online help or the MSDN website.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.12.240