X is for… XML Literal
XML Literal(s) is a feature that Visual Basic developers can call their own! The XML Literal syntax facilitates creating XML documents and elements that support the vast majority of the XML 1.0 specification. Complementing the literals are axis properties that aid in navigating and accessing XML elements and attributes.
Let’s start with an example. Below is an XML literal representing a menu; as you can see it’s assigned directly to a variable – here relying on implicit typing.
Dim xml = <menu>
<course name="appetizer">
<dish>Shrimp Cocktail</dish>
<dish>Escargot</dish>
</course>
<course name="main">
<dish>Filet Mignon</dish>
<dish>Garlic Potatoes</dish>
<dish>Broccoli</dish>
</course>
<course name="dessert">
<dish>Chocolate Cheesecake</dish>
</course>
</menu>
So what is the type of the xml
variable? It’s a System.Xml.Linq.XElement
, which certainly brings to the forefront the synergy with LINQ (Language Integrated Query). Underneath the covers, the Visual Basic compiler calls the relevant constructors (XElement
, XAttribute
, etc.) to create the LINQ to XML object.
Note though that xml
in the following snippet is an XDocument
, because of the inclusion of the xml version tag.
Dim xml = <?xml version="1.0"?>
<menu>
<course name="appetizer">
<dish>Shrimp Cocktail</dish>
<dish>Escargot</dish>
</course>
</menu>
LINQ within XML Literals
You can include LINQ expressions with your literals as well, using an embedded expression syntax reminiscent of ASP! The following code yields the same XML as the first example, but populates it using LINQ to Objects from a hard-coded list; of course, that data could just as easily come from a database or some other external source.
Dim menu As List(Of Dish) = New List(Of Dish)()
menu.Add(New Dish("appetizer", "Shrimp Cocktail"))
menu.Add(New Dish("appetizer", "Escargot"))
menu.Add(New Dish("main", "Filet Mignon"))
menu.Add(New Dish("main", "Garlic Potatoes"))
menu.Add(New Dish("main", "Broccoli"))
menu.Add(New Dish("dessert", "Chocolate Cheesecake"))
Dim xml = <?xml version="1.0"?>
<menu>
<course name="appetizer">
<%= From m In menu _
Where m.Course = "appetizer" _
Select <dish><%= m.Food %></dish> _
%>
</course>
<course name="main">
<%= From m In menu _
Where m.Course = "main" _
Select <dish><%= m.Food %></dish> _
%>
</course>
<course name="dessert">
<%= From m In menu _
Where m.Course = "dessert" _
Select <dish><%= m.Food %></dish> _
%>
</course>
</menu>
XML literals can also be traversed via LINQ to XML. For instance, the following snippet will result in a list of each of the dishes, without any XML markup.
Dim dishList = From d In xml.Descendants("dish") _
Select d.Value
For Each item In dishList
Console.WriteLine(item)
Next
Axis Properties
Axis properties are a series of syntax elements that enable you to access elements and attributes within the XML. There are three different properties that we’ll take a look at next.
Child axis
The child axis property returns all child elements of the source element. The property is denoted by placing angle brackets around the child elements desired. For example, this code
Dim childAxis = xml.<menu>.<course> For Each item In childAxis Console.WriteLine(item) Next
results in
<course name="appetizer">
<dish>Shrimp Cocktail</dish>
<dish>Escargot</dish>
</course>
<course name="main">
<dish>Filet Mignon</dish>
<dish>Garlic Potatoes</dish>
<dish>Broccoli</dish>
</course>
<course name="dessert">
<dish>Chocolate Cheesecake</dish>
</course>
Descendant axis
The descendant axis property returns all elements under the source element, regardless of how deeply they are nested. This property is denoted by placing angle brackets around the element desired and separating it from the source element with three periods. For example, the following code produces the same XML as shown for the child axis example above.
Dim childAxis = xml...<course> For Each item In childAxis Console.WriteLine(item) Next
You can use indexing as well, for instance, to get only the last course, dessert, via the following line
Dim course3 = xml...<course>(2)
Attribute axis
The attribute axis returns the specified attribute (denoted by the @ symbol) of the element on which it operates. For instance, the following code will print out the three courses: appetizer, main, and dessert.
Dim childAxis = xml...<course> For Each item In childAxis Console.WriteLine(item.@name) Next
For more information on using XML Literals with Visual Basic, check out the MSDN topic, XML in Visual Basic. And for those of you using C#, there’s a neat little add-in that will paste the code necessary to create the XML document that you have stored on the clipboard. Here’s how:
Extract the
LinqSamples\PasteXmlAsLinq
directory fromC:\Program Files\Microsoft Visual Studio 9.0\Samples\1033\CSharpSamples.zip
Build the PasteXmlAsLinq solution
Copy the
PasteXmlAsLinq.dll
andPasteXmlAsLinq.Addin
files into the Addins folder. This folder is located atMy Documents/Visual Studio/Addins
, but you may need to create it explicitly.Restart Visual Studio.
If you have XML in the clipboard (perhaps copied from some other source), you’ll see a Paste XML as XElement menu option in the Edit menu:
Copying the XML literal syntax from the first Visual Basic example in this post into the clipboard and then pasting into a C# script using the menu item above yields the following:
XElement xml = new XElement("menu", new XElement("course", new XAttribute("name", "appetizer"), new XElement("dish", "Shrimp Cocktail"), new XElement("dish", "Escargot") ), new XElement("course", new XAttribute("name", "main"), new XElement("dish", "Filet Mignon"), new XElement("dish", "Garlic Potatoes"), new XElement("dish", "Broccoli") ), new XElement("course", new XAttribute("name", "dessert"), new XElement("dish", "Chocolate Cheesecake") ) );
It’s not exactly an XML literal, but certainly saves a lot of typing!