XElement and XDocument in LINQ to XML
LINQ to XML revolutionized XML processing in .NET by introducing
functional construction, an approach that allows developers to construct
entire XML trees declaratively in a single expression. At the core of
this capability are the XElement and XDocument
classes. This article explores how both classes enable functional tree
construction, how they differ, and how they simplify building,
transforming, and querying XML structures compared to traditional DOM
models.
Understanding Functional Construction
Functional construction is a programming paradigm where an XML tree
is created through nested constructor calls rather than sequential,
imperative DOM manipulation. In traditional APIs like
XmlDocument, building an XML hierarchy requires creating a
document, creating individual nodes, setting values, and appending
children step-by-step. LINQ to XML replaces this verbose approach with
parameterized constructors that accept content collections, LINQ
queries, and scalar values directly.
The Role of XElement
XElement is the fundamental building block of XML
functional construction in .NET. It represents an XML element and
contains the logic necessary to hold attributes, child elements,
comments, and text nodes.
The power of XElement lies in its flexible
constructor:
public XElement(XName name, params object[] content);The params object[] content parameter makes functional
construction possible. It accepts virtually any object type and
automatically converts it into valid XML content: *
XAttribute objects become attributes of
the element. * XElement objects become
nested child elements. * Strings and primitive types
become text nodes. * IEnumerable
collections (including LINQ query results) are flattened, and
each item is added to the element. * null
values are silently ignored, making conditional element
creation straightforward.
Because XElement can act as the root of its own subtree,
developers often use XElement without needing an
overarching document container.
The Role of XDocument
While XElement handles individual elements and subtrees,
XDocument represents the complete XML document. It provides
top-level document capabilities that a standalone XElement
cannot represent alone:
- XML Declarations (
XDeclaration): Specifies the XML version, encoding, and standalone status. - Document Type Definitions
(
XDocumentType): Specifies DTD information. - Top-level Processing Instructions and Comments: Allows placement of instructions or comments outside the root element.
XDocument uses a similar constructor accepting
params object[] content, allowing the entire document—from
declaration to root element—to be defined functionally.
Functional Construction in Practice
Combining XDocument, XElement, and LINQ
queries demonstrates the full power of functional construction:
var employees = new[]
{
new { Id = 101, Name = "Alice", Department = "Engineering" },
new { Id = 102, Name = "Bob", Department = "Marketing" }
};
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment("Employee Roster"),
new XElement("Company",
new XAttribute("generated", DateTime.UtcNow),
new XElement("Employees",
from emp in employees
select new XElement("Employee",
new XAttribute("id", emp.Id),
new XElement("Name", emp.Name),
new XElement("Department", emp.Department)
)
)
)
);When to Use XElement vs. XDocument
- Use
XDocumentwhen you need to serialize a full XML document that requires an XML declaration, a DTD, or comments and processing instructions outside the root element. - Use
XElementwhen building XML fragments, working with APIs (like REST endpoints or SOAP payloads) that consume element trees directly, or performing tree transformations where top-level document metadata is unnecessary.