VB XML Cookbook, Recipe 2: Descendants and Ancestors (Doug Rothaus)

This entry in the cookbook shows how you can access descendant and ancestor elements in an XML document using Visual Basic, XML Axis properties, and LINQ to XML objects.

Descendants

Visual Basic provides XML Axis properties that enable you to easily refer to child nodes and attributes. As is often the case with XML, you may need to reference sub-elements that show up in different levels of the XML hierarchy. In that case, you can use the XML Descendant axis property.

The XML Descendant axis property is identified using three periods followed by the XML element that you want to refer to. For example, in the AdventureWorks contacts source document that we used in Recipe 1 (you can download the XML document and related schemas from the Recipe 1 post), there is an <AdditionalContactInfo> element that contains information about the contact such as phone numbers, shipping and billing addresses, and so on. The phone numbers in the content of the <AdditionalContactInfo> element can show up anywhere within the value of the element. As a result, you would need to use the XML Descendant axis property to refer to the phone number elements. For example:

The XML descendant axis property returns a collection of all of the matching elements “down” the XML hierarchy. Let’s look at a more complete example. The following Function returns a list of contact names and phone numbers using the XML Descendant axis property.

It is important to note that you should not use the XML Descendant axis property when the location of a sub-element is always the same. Your code will perform much better if you use the XML Child axis property to refer to a specific location in the XML hierarchy than if you use the XML Descendant axis property to search the entire XML hierarchy for matches.

Ancestors

XML Axis properties make searching “down” the XML hierarchy quick and easy. However, what if you need to search “up” the XML hierarchy? In that case, you can use the Ancestors method of the XNode class. Because XML literals expose the functionality of LINQ to XML classes, you can use the additional capabilities of those LINQ to XML classes when the need arises.

The Ancestors() method searches “up” the XML hierarchy for an XML element that matches the supplied element name. The element name that you supply to the Ancestors method, however, must include the XML namespace for the element as well. You can use the GetXmlNamespace operator to return an XML namespace based on a supplied XML prefix. For the default XML namespace, call the GetXmlNamespace operator and don’t pass it a prefix. If you are searching for an element in the same XML namespace as an element that you already have a reference to, you can access the XML namespace of the referenced element using the Name.Namespace property.

For example, the following sample takes a list of <telephoneNumber> elements (actually, any element of type phoneNumberType as identified in the ContactTypes.xsd file) from the AdventureWorks contacts sample document and returns a list of the phone numbers as well as the name of the related contact for the phone number. The sample calls the Ancestors() method to search up the XML hierarchy for the owning <Contact> node.