Distinct List of attribute values from XML, using a pre-defined set of attribute names I have an XML stream that looks like the following (attribute and node quantity , and node depth reduced for demonstration purposes.)

&lt;itinerary&gt;
  &lt;organizer&gt;
    &lt;company name="ACME" billingLocation="London" adminOffice="Manchester"&gt;
  &lt;/organizer&gt;
  &lt;traveller name="John Smith" homeCity="London" /&gt;
  &lt;flight date="20160317" code="BA101" origin="London" destination="New York" /&gt;
  &lt;vehicleHire start="20160317" end="20160317"&gt;
    &lt;depot type="pickup" location="London" /&gt;
    &lt;depot type="return" location="Heathrow" /&gt;
  &lt;/vehicleHire&gt;
  &lt;hotel location="New York" checkin="20160317" checkout="20160318" /&gt;
  &lt;journey&gt;
    &lt;train date="20160318"&gt;
      &lt;origin station="New York" /&gt;
      &lt;destination station="Boston" /&gt;
    &lt;/train&gt;
&lt;/itinerary&gt;


I'd like to get a distinct list of attribute values where the attribute name is in (billingLocation,adminOffice,homeCity,origin,destination,location,station), but my final/actual list of attribute names will number around 30.

I have this C# code working using XmlDocument and an XPath query, but I'm unsure if this is the most efficient method.

XmlDocument xd = new XmlDocument();
xd.Load(customProvider.GetStream());
XmlNodeList nl = xd.SelectNodes(@"//@billingLocation|//@adminOffice|//@homeCity|//@origin|//@destination|//@location|//@station");
var lst = nl.Cast&lt;XmlAttribute&gt;().Select(a =&gt; a.Value).Distinct().ToList();


The final XML will be more complex and have a deeper hierarchy, and the attributes might occur across different nodes.

Is XmlDocument and XPath the most efficient aproach, or would Linq to XML perhaps be faster, and what would that look like?
As long as you don't face noticable performance issues I would chose whatever method seems to be better for you. The XPath works so you may stick to it.

I would however build the path in a more generic way by specifying an array of attribute names first:

var attributeNames = new[]
{
    "billingLocation",
    "adminOffice",
    "homeCity",
    "origin",
    "destination",
    "location",
    "station"
}


and the combining them into a query:

var xPath = string.Join("|", attributeNames.Select(n =&gt; $"//@{n}"));
...xd.SelectNodes(xPath);




In this cas however it is a little bit easier to do the same with linq:

Parse the xml first (which is btw invalid in your example - some elements are not closed):

var xElement = XElement.Parse(text);


Then use the same array for the linq query:

var cities =
    (from attr in xElement.Descendants().Attributes()
     where attributeNames.Contains(attr.Name.LocalName)
     select attr.Value).Distinct();