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.


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:

Dim xmlDoc = XDocument.Load(“AWContacts.xml”)


‘ Return all descendant <telephoneNumber> elements

Dim telephoneNumbers = _



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.

Imports <xmlns=http://SampleSchema/AWContacts>

Imports <xmlns:s=sample-output>

Imports <xmlns:aci=http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo>

Imports <xmlns:act=http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes>


Public Class Recipe2


  Public Function GetPhoneNumbers(ByVal xmlDoc As XDocument) As XElement

    Return <s:ContactPhoneNumbers>

             <%= From contact In xmlDoc.<Contacts>.<Contact> _

                 Where contact.<aci:AdditionalContactInfo><act:telephoneNumber>.<act:number>.Count > 0 _

                 Select <s:Contact>

                          <s:Name><%= contact.<FirstName>.Value & ” “ & _

                                      contact.<LastName>.Value %></s:Name>


                            <%= From number In _

                                contact.<aci:AdditionalContactInfo><act:telephoneNumber>.<act:number> _

                                Select <s:Number><%= number.Value %></s:Number> _



                        </s:Contact> _



  End Function

End Class

In XSLT, the same transform would look like the following:

<?xml version=1.0?>









<xsl:output method=xml indent=yes />


  <xsl:template match=aw:Contacts>


      <xsl:apply-templates select=aw:Contact />




  <xsl:template match=aw:Contact>

    <xsl:if test=count(aci:AdditionalContactInfo//act:telephoneNumber/act:number) > 0>