Home > Extreme Programming, Uncategorized > Working with XML Namespaces and LINQ

Working with XML Namespaces and LINQ

Ben XML Namespaces

October 11th 2010 | Ben Yoder

Working with XML Namespaces and LINQ

While working on a project using LINQ to XML to parse a web response, I ran into an issue whereby my calls to get an entity’s Descendants or Elements were returning no results. It turned out that the specified response included a namespace. In this case you can’t use the common element name—you must get the fully qualified XName.

For example, given the following XML and LINQ Query:

    string xml = @"<Employees>
      <Employee>
        <FirstName>John</FirstName>
        <LastName>Smith</LastName>
        <Id>1</Id>
      </Employee>
    </Employees>";

        XElement employee = XElement.Parse(xml);

    var employees = from e in employee.Descendants("Employee")
                        select new
                        {
                            Id = e.Element("Id").Value,
                            FirstName = e.Element("FirstName").Value,
                            LastName = e.Element("LastName").Value
                        };

The query works and the employees object contains John Smith. However if the XML changes, the query returns nothing:

    <h:Employees xmlns:h="http://www.w3.org">
      <h:Employee>
        <h:FirstName>John</h:FirstName>
        <h:LastName>Smith</h:LastName>
        <h:Id>1</h:Id>
      </h:Employee>
    </h:Employees>

After browsing through some MSDN documentation, I learned that I have to include the namespace in the query. I got the full name using XName.Get()

    XName root = XName.Get("Employee", "http://www.w3.org");
    XName firstName = XName.Get("FirstName", "http://www.w3.org");
    XName lastName = XName.Get("LastName", "http://www.w3.org");
    XName id = XName.Get("Id", "http://www.w3.org");

Replace the names in the LINQ query and it returns the correct results. Of course, there are other ways to accomplish this. You could create an XNamespace object based on the namespace string and prepend it to each element name in the query. Creating an individual XName object for each query parameter gets kind of verbose, so for more complex LINQ this is probably not the preferred way.

Ben Yoder is a Senior .NET developer at Thycotic Software, an agile software services and product development company based in Washington DC. Secret Server is our flagship password management software product.

  1. Richard
    October 21, 2010 at 6:32 pm

    The simplest option would probably be to get the XNamespace from the element. This would work with or without a declared namespace without having to hard-code the namespace URI.

    Also, it’s worth remembering that “e.Element(name).Value” will throw an exception if the element doesn’t exist; “(string)e.Element(name)” will simply return null.

    var ns = employee.Name.Namespace;
    var employees = from e in employee.Descendants(ns + “Employee”)
    select new
    {
    Id = (string)e.Element(ns + “Id”),
    FirstName = (string)e.Element(ns + “FirstName”),
    LastName = (string)e.Element(ns + “LastName”),
    };

    • Ben
      December 1, 2010 at 2:32 am

      Agreed, the XNamespace is a much cleaner way to go. As I mentioned, the individual XNames get out of hand with larger queries. Thanks for the tip and example regarding ‘e.Element(name).Value’, I was unaware of that distinction.

  2. tranmanhtan
    June 1, 2011 at 3:07 am

    If you are struggling with xml namespaces, there is a great tutorial on xpath namespaces at xml reports. It walks you through it in very simple steps

    xml reports

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: