Declarative XML Generation with VB.NET XML Literals
Learn how to use VB.NET XML literals to generate well-formed XML documents declaratively, avoiding the pitfalls of string concatenation and the verbosity of XmlWriter.
24 Nov 2025, 18:57 UTC

The Problem with String-Based XML
Generating XML documents often leads to a choice between two extremes: the verbose, imperative approach of using XmlWriter or the dangerous, error-prone approach of string concatenation. When you use strings to build XML, you manually handle angle brackets and quotes, which frequently leads to malformed documents or security vulnerabilities like XML injection if user input isn't perfectly escaped.
The solution in VB.NET is XML Literals. Unlike C#, VB.NET allows you to embed XML directly into your source code. The compiler treats these literals as first-class objects (specifically XElement or XDocument from the System.Xml.Linq namespace), ensuring the resulting XML is always well-formed and automatically encoded.
How XML Literals Work
An XML literal is simply XML written inside your VB code. To make these literals dynamic, VB uses embedded expressions. By using the <%= ... %> syntax, you can inject variables, function calls, or LINQ queries directly into the XML structure.
Beyond simple insertion, VB.NET provides XML Axis Properties. These are shorthand notations for navigating XML trees. For example, if you have an object doc, you can access a child element using doc.<childName> or an attribute using doc.@attributeName. This removes the need for repetitive Element("name") or Attribute("name") method calls.
Worked Example: Generating an Invoice
Consider a scenario where you have a list of order items and need to generate a formatted XML invoice. Instead of looping through a list and appending strings, you can project the data directly into a literal template.
Imports System.Xml.Linq
Module InvoiceGenerator
Sub Main()
' Sample data
Dim orders = New List(Of Order) From {
New Order With {.Id = 101, .Item = "Mechanical Keyboard", .Price = 120.0},
New Order With {.Id = 102, .Item = "USB-C Hub", .Price = 45.5},
New Order With {.Id = 103, .Item = "Ergonomic Mouse", .Price = 80.0}
}
Dim customerName As String = "Acme Corp & Co"
Dim invoiceDate As String = DateTime.Now.ToString("yyyy-MM-dd")
' The XML Literal: declarative structure with embedded LINQ
Dim invoiceDoc = <Invoice date="%= invoiceDate %">
<Customer>%= customerName %</Customer>
<Items>
<%= From o In orders
Select <Line id="%= o.Id %">
<Product>%= o.Item %</Product>
<Price>%= o.Price %</Price>
</Line>
%>
</Items>
</Invoice>
' Save to file
invoiceDoc.Save("invoice.xml")
Console.WriteLine("Invoice generated successfully.")
End Sub
Public Class Order
Public Property Id As Integer
Public Property Item As String
Public Property Price As Decimal
End Class
End Module
Implementation Details
- Execution Environment: Run this in a .NET Console Application. Ensure
System.Xml.Linqis referenced (included by default in most modern .NET SDK templates). - Permissions: The application requires write permissions to the local directory to execute
.Save(). - Encoding: Note that
customerNamecontains an ampersand (&). The XML literal automatically encodes this as&, preventing the XML from becoming invalid.
Trade-offs and Limitations
While XML literals significantly improve readability, there are two primary constraints to consider:
- Language Lock-in: XML literals are a unique feature of VB.NET. If your organization decides to migrate a project to C#, these literals cannot be ported directly; they must be rewritten using the
XElementconstructor syntax. - Memory Overhead: XML literals create an in-memory tree (DOM). For extremely large datasets—such as exporting millions of rows to XML—this can lead to high memory consumption or
OutOfMemoryException. In those specific high-throughput cases, the streamingXmlWriteris a more performant, albeit more verbose, choice.
Verifying the Result
To verify that your XML literal is behaving as expected, you can print the object to the console before saving:
Console.WriteLine(invoiceDoc.ToString())
Check for two things: first, that the hierarchy matches your template, and second, that any special characters in your data (like <, >, or &) have been converted to their corresponding XML entities. If the output is a valid XML string and the memory usage remains stable for your data size, the literal approach is the optimal engineering choice for the task.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.