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:

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