`XmlFluentValidator`: Code-First XML Validation That Stays Close to Your Rules
Source: Dev.to
The Problem / Difficulties with Traditional XML Validation
XSD has its own power, but it comes with real trade‑offs:
- Low readability and poor discoverability.
- Limited expressiveness for cross‑element or computed rules.
- Hard to evolve alongside application logic.
- No (or very poor) natural place for business‑level validation semantics.
Pure runtime validation often results in:
- Custom XPath logic duplicated across projects.
- No formal schema to share with consumers.
- Inconsistent validation behavior between runtime and contracts.
XmlFluentValidator can help you close part of this gap.
What XmlFluentValidator Is
XmlFluentValidator is a .NET Standard 2.0 library that allows you to:
- Define XML validation rules using a fluent, strongly‑typed C# API.
- Validate XML documents at runtime with structured error output.
- Set documentation, severity, and messages on rules.
- Combine schema validation with custom runtime logic.
- Generate XSD schemas from rules (supported and evolving).
It treats validation rules as first‑class code artifacts, not static XML files.
Core Design Principles
-
The Code Is the Source of Truth
Validation rules live in C#, alongside your domain logic. No duplication between schema files and runtime validation. -
Fluent, Intent‑Driven API
Rules read like requirements, not infrastructure:- What element is required?
- What constraints apply?
- Why does this rule exist?
-
Runtime + Schema Compatibility
Rules are designed to map cleanly to XSD constructs where possible, while still allowing runtime‑only logic when necessary.
Defining Validation Rules
At the core of the library is a fluent builder that targets paths, elements, and attributes.
Element Rules
var validator = new XmlFluentValidator()
.ForPath("/order/id")
.WithElementRequired("Order ID is required")
.WithElementMatchesRegex(@"^\d+$", "Order ID must be numeric")
.Done()
.ForPath("/order/total")
.WithElementInRange(0, 10000, true, "Total must be between 0 and 10000")
.Done();
This expresses clearly:
- The element must exist.
- The value must follow a specific format.
- The value must be within a valid numeric range.
No XSD syntax. No XPath boilerplate.
Attribute Validation
validator
.ForPath("/order/items/item")
.WithAttributeRequired("sku", "SKU is mandatory")
.WithAttributeMatchesRegex("sku", @"^[A-Z0-9\-]+$")
.WithAttributeInRange("quantity", 1, 100, true)
.Done();
This avoids the common XSD problem where attribute rules are hard to read or scattered.
Cardinality, Length, and Uniqueness
The API supports common structural constraints:
- Element existence (required / optional).
- Maximum occurrences.
- Value length (min, max, exact).
- Uniqueness across sibling nodes.
- Data‑type enforcement.
- Nullable (
xs:nillable) control.
All of these can also be documented and messaged directly in code.
Custom and Global Rules
Some rules cannot be expressed in XSD at all (e.g., cross‑element logic, computed totals, document‑wide constraints). XmlFluentValidator supports global rules:
validator.GlobalRule(doc =>
{
var items = doc.XPathSelectElements("/order/items/item");
return items.Any();
}, "Order must contain at least one item");
These rules:
- Run at runtime.
- Participate in the same validation pipeline.
- Produce structured error messages.
- Can coexist with schema validation.
This is one of the strongest differentiators of the library.
Validation Execution and Results
var result = validator.Validate(xDocument);
if (!result.IsValid)
{
foreach (var error in result.Errors)
{
Console.WriteLine($"{error.Path}: {error.Message}");
}
}
Each validation error includes:
- The XML path.
- The violated rule.
- The configured message.
- Severity metadata.
This makes the output suitable for:
- APIs.
- Logging.
- Automated tests.
XSD Schema Generation
A key goal of XmlFluentValidator is schema generation from fluent validation rules. Rules such as:
- Required elements.
- Data types.
- Ranges.
- Enumerations.
- Documentation annotations.
can be emitted into an XSD representation. This allows you to:
- Share contracts with external systems.
- Keep schemas aligned with runtime validation.
- Avoid maintaining two parallel validation artefacts.
XmlFluentValidator bridges the gap between code‑first validation and contract‑first schema generation, giving you a single source of truth for XML validation.
How It Fits into Real Systems
XmlFluentValidator is especially useful when:
- XML validation rules evolve frequently.
- Business logic must be enforced beyond XSD capabilities.
- Validation must run dynamically at runtime.
- Schemas still need to be shared or documented.
- Validation logic belongs with application code, not static files.
Typical use cases include:
- Integration gateways
- Configuration validation
- ETL pipelines
- Legacy XML modernization
- Domain‑specific XML formats
Final Thoughts
XmlFluentValidator is not trying to replace XSD.
It aims to make XML validation more expressive, maintainable, and aligned with the way modern .NET developers think.
If you also believe:
- validation rules should read like business rules
- code should be the primary source of truth
- schemas should be generated, not hand‑crafted
then XmlFluentValidator is worth your attention.
🔗 Repository:
