Page 1 of 1

Query XML with XElement and LINQ to XML Rate Topic: ***** 1 Votes

#1 andrewsw  Icon User is offline

  • the case is sol-ved
  • member icon

Reputation: 6374
  • View blog
  • Posts: 25,755
  • Joined: 12-December 12

Posted 02 April 2015 - 10:07 AM

This tutorial demonstrates, and provides examples of, querying an XML document using an XElement. It demonstrates the use of XElement and LINQ extension methods (method syntax) and LINQ query expressions (expression syntax).

There are many ways to query (parse) XML, perhaps too many. Using an XDocument or XElement is preferable to the older technology of XMLdocument. (I believe XDocument was introduced in .NET 3.5.) XDocument uses LINQ to SQL, enabling query expression syntax (From.. Select..).

XPath is another approach. XPath is powerful, and is not specific to .NET or Microsoft, but the expression syntax requires a little effort to master.

System.Xml.Linq Namespace :MSDN
XDocument Class :MSDN
Introduction to LINQ in Visual Basic :MSDN
XPath Examples :MSDN

The various approaches can actually be combined when parsing a single XML document. This gives us a lot of choices but can also be overwhelming for a beginner. Working with an XElement is both powerful and relatively straightforward, as I hope to show in this tutorial.



I've mentioned both XDocument and XElement. An XDocument includes the XML declaration, XML Document Type (DTD) and any processing instructions. XDocument also contains a single root XElement. You might obtain an XDocument and then use:
    Dim xml As XElement = xmlDoc.Root


and the bulk of your work, querying, will be against this (simpler) object. You'll see this in the code.



Our XML Document

I've borrowed a Microsoft sample XML file, books.xml:

Sample XML File (books.xml)

I've modified it though, to include <tags> with <tag> elements so that I can demonstrate querying nested elements. The revised file is posted here within the spoiler.

Spoiler



To load the XML from a file you could use:
Dim xmlDoc As XDocument = Xdocument.Load("c:\users\andrew\documents\books.xml")


Alternatively, to keep the tutorial code all in a single file, you could use an XML literal. Here is the initial part of the code for creating an XML literal:
        Dim xmlDoc As XDocument = <?xml version="1.0"?>
                                  <catalog>
                                      <book id="bk101">
                                          <author>Gambardella, Matthew</author>
                                          <title>XML Developer's Guide</title>
                                          <genre>Computer</genre>
                                          <price>44.95</price>


Start a new Console application and either load the XML from a file or use an XML literal.

Hint: Type Dim xmlDoc As XDocument = and then paste the entire XML (from the spoiler) after the equals sign. Visual Studio will recognise that you are defining an XML literal and format it.
        Dim xml As XElement = xmlDoc.Root

        Dim books As IEnumerable(Of XElement) = xml.Elements


If you don't need the extra features of XDocument then you could load an XElement directly:
Dim theXml As XElement = XElement.Load("c:\users\andrew\documents\books.xml")


I don't do this in this tutorial, and the querying will be against the books enumerable.

A simple first example is just to output the list of books to the console:
        For Each book In books
            Console.WriteLine(book)    'XML output
        Next


The console is capable of displaying the XML output. Notice that the catalog (the root) element is not included in the enumerable, it is just a collection of the book elements.

List the content, the text, of a named element (tag)
        'list all the book titles
        Console.WriteLine("Book titles:")
        For Each book In books
            Console.WriteLine(book.Element("title").Value)
        Next

        'XML Developer's Guide
        'Midnight Rain
        'Maeve Ascendant
        'Oberon()'s Legacy
        'The Sundered Grail
        'Lover Birds
        'Splish Splash
        'Creepy Crawlies
        'Paradox Lost
        'Microsoft .NET: The Programming Bible
        'MSXML3: A Comprehensive Guide
        'Visual Studio 7: A Comprehensive Guide


You will hear the terms tag, node and element used interchangeably. Tag is more commonly used with HTML, and element is the term that the official XML documentation uses. People tend to use the term node when talking more formally about a document structure (rather than about specific document content). Unfortunately, it is too late to persuade people to use consistent terminology.

Note that we need to use .Value to obtain the text within the Element.

Read grouped element's content
        Console.WriteLine("Titles and Authors:")
        For Each book In books
            Console.WriteLine("Title: {0}, Author: {1}", _
                              book.Element("title").Value, book.Element("author").Value)
        Next


Note that it is a little tricky to always think of good, descriptive, titles for each piece of code. It will help you later (when searching this tutorial) if you consider that I start with simple examples and move to more complex examples.

Method syntax: Take(), OrderBy(), OrderByDescending()

The following code demonstrates using Enumerable methods (Take(), OrderBy()) to obtain information from the first two books.
        Dim firstTwo = books.Take(2).OrderBy(Function(x) x.Element("title").Value)
        For Each book In firstTwo
            Console.WriteLine(book.Element("title").Value)
        Next

        'Midnight Rain
        'XML Developer's Guide


Test this by changing OrderBy() to OrderByDescending(). This will prove that the code works and demonstrate a third Enumerable method.

Query expression syntax (From..)

Lists just those books where their genre tag contains the text "Computer".
        Console.WriteLine("Just Computer Books:")
        Dim compBook = From bk In books
                       Where CStr(bk.Element("genre")) = "Computer"
                       Select bk
        For Each book As XElement In compBook
            Console.WriteLine(book.Element("title").Value)
        Next
        'XML Developer's Guide
        'Microsoft .NET: The Programming Bible
        'MSXML3: A Comprehensive Guide
        'Visual Studio 7: A Comprehensive Guide


You can choose to use expression or method syntax, and they can even be combined. Expression syntax is similar to SQL but notice that the word From occurs first.

Note also that, in the query expression, we don't always have to explicitly use .Value. Outside of a query expression we most often will need to use .Value.

Select by attribute value

Our sample file only has a single attribute, the id. If you wanted to find a specific id you could change the following to use:
    Where CStr(bk.Attribute("id")) = "bk102"


I demonstrate a slightly more sophisticated example using the Like operator.
        Console.WriteLine("Select by Attribute 'id' (#1#)")
        Dim bookWith1 = From bk In books
                     Where CStr(bk.Attribute("id")) Like "bk#1#"
                     Select bk
        For Each book As XElement In bookWith1
            Console.WriteLine(book.Element("title").Value)
        Next

        'Microsoft .NET: The Programming Bible
        'MSXML3: A Comprehensive Guide
        'Visual Studio 7: A Comprehensive Guide


The hash-sign is a placeholder for a number, whereas a question mark would represent a character (a letter or number).

Search nested tags

List the titles of all books having the tag "Microsoft":
        Console.WriteLine("Books/Microsoft:")
        Dim bookMS = From bk In books
                     Where bk.Element("tags").Elements("tag"). _
                        Count(Function(x) x.Value = "Microsoft") > 0
                     Select bk
        For Each book In bookMS
            Console.WriteLine(book.Element("title").Value)
        Next
        'Microsoft .NET: The Programming Bible
        'MSXML3: A Comprehensive Guide
        'Visual Studio 7: A Comprehensive Guide


I'm sure there are many other ways to achieve this; this is the way that occurred to me, using Count(). (If you have an alternative I would be interested to see it, please include it in a response below.)

Get unique list of nested tag-values

List all the unique tags. This example demonstrates the use of the Let, Order By and Distinct clauses.
        Console.WriteLine("Unique tags, ordered:")
        Dim tagList = From tag In books.Descendants("tags").Elements("tag")
                      Let x = tag.Value
                      Order By x
                      Select x
                      Distinct

        For Each tag In tagList
            Console.WriteLine(tag)
        Next

        'conference
        'England
        'Heisenberg
        'insects
        'love
        'Microsoft
        'NET
        'quantum
        'sea
        'sequel
        'society
        'sorcery
        'XML
        'XSLT
        'zombies


Group By and Count
        Dim genres = From book In books
                     Group By Genre = book.Element("genre").Value
                     Into BookGenres = Group, Count()

        For Each grp In genres
            Console.WriteLine("{0} {1}", grp.Genre, grp.Count)
        Next

        'Computer 4
        'Fantasy 4
        'Romance 2
        'Horror 1
        'Science Fiction 1

This post has been edited by andrewsw: 02 April 2015 - 05:58 PM


Is This A Good Question/Topic? 2
  • +

Replies To: Query XML with XElement and LINQ to XML

#2 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon

Reputation: 2298
  • View blog
  • Posts: 9,535
  • Joined: 29-May 08

Posted 02 April 2015 - 12:49 PM

Few more examples of XML Liiterals
Was This Post Helpful? 0
  • +
  • -

#3 andrewsw  Icon User is offline

  • the case is sol-ved
  • member icon

Reputation: 6374
  • View blog
  • Posts: 25,755
  • Joined: 12-December 12

Posted 02 April 2015 - 01:05 PM

Thank you. I was struggling to think what those symbols .. @ would be called, XML operators. Turns out they are called XML properties.
Was This Post Helpful? 0
  • +
  • -

#4 IronRazer  Icon User is offline

  • Custom Control Freak
  • member icon

Reputation: 1444
  • View blog
  • Posts: 3,674
  • Joined: 01-February 13

Posted 13 October 2015 - 04:51 PM

Thanks andrewsw, i have been struggling for a few days to try understanding how to read/write xml files and this just helped me with the reading part by using the XElement. 8)
Was This Post Helpful? 0
  • +
  • -

#5 andrewsw  Icon User is offline

  • the case is sol-ved
  • member icon

Reputation: 6374
  • View blog
  • Posts: 25,755
  • Joined: 12-December 12

Posted 13 October 2015 - 05:12 PM

Thanks. For the writing part:

XElement.Save(filename)

There are several overloads.

Simple writing and reading example (C#).

Modifying Elements, Attributes, and Nodes in an XML Tree

This post has been edited by andrewsw: 13 October 2015 - 05:18 PM

Was This Post Helpful? 1
  • +
  • -

Page 1 of 1