Codebelt

Cuemon.Extensions.Xml

XML reader, writer, stream, and converter extensions for the Cuemon XML stack.

.NET 10.0 / .NET 9.0 MIT v10.5.3 46,537 downloads

Overview

Cuemon.Extensions.Xml adds focused extension methods around XmlReader, XmlWriter, Stream, string, and related XML serialization types. It builds on Cuemon.Xml and the System.Xml stack for common engineering tasks such as copying documents with new writer settings, removing namespace declarations, splitting large documents into smaller readers, and writing objects directly to an existing XML writer.

The package also covers adjacent authoring and parsing workflows through XElement parsing helpers, XML-safe string sanitization, and list helpers for registering XmlConverter instances. It works best as the ergonomic layer around Cuemon's XML serializer model rather than as a separate XML object model.

Key APIs

ToXmlReader is exposed for byte[], Stream, and Uri so callers can open XML from common inputs without rebuilding reader setup for each source. The stream overload accepts XmlReaderSettings and can infer the XML encoding when no explicit encoding is supplied.

CopyXmlStream clones an XML Stream into a new in-memory stream using caller-supplied XmlWriterSettings. The test suite uses it to re-emit the same document as UTF-16, UTF-32, and ISO-8859-1 while preserving the original seek position when the source stream supports seeking.

RemoveXmlNamespaceDeclarations rewrites a stream without namespace declarations. It is useful when downstream code expects local element names and does not tolerate prefixed XML.

Chunk splits an XmlReader into a sequence of smaller readers, each holding up to a caller-supplied number of depth-1 elements under the original root. It fails fast if the reader has already advanced past its initial state, which keeps chunk boundaries deterministic.

ToHierarchy converts an XmlReader into IHierarchy<DataPair>. The tests show it preserving attributes and nested elements, which makes it practical for traversal and assertions without building a DOM first.

WriteObject serializes an object into an existing XmlWriter, and the related WriteEncapsulatingElementWhenNotNull and WriteXmlRootElement helpers cover wrapped or explicitly named root scenarios. This is the package's bridge between Cuemon's XML formatter pipeline and manual writer-based output.

AddXmlConverter<T> and InsertXmlConverter<T> register custom XmlConverter implementations on IList<XmlConverter>, while specialized helpers such as AddEnumerableConverter, AddUriConverter, AddDateTimeConverter, and AddExceptionConverter cover common shapes without custom boilerplate.

TryParseXElement in Cuemon.Extensions.Xml.Linq turns XML text into XElement with optional LoadOptions, and IsXmlString gives a lighter validity check when a boolean is enough.

SanitizeXmlElementName and SanitizeXmlElementText clean dynamic names and text before writing them into XML. The text sanitizer also has a CDATA-aware mode for stripping invalid control characters and unsafe ]]> sequences.

Basic usage

using System.IO;
using System.Linq;
using System.Xml;
using Cuemon.Extensions.Xml;
using Codebelt.Extensions.Xunit;
using Xunit;

namespace Contoso.Integration.Tests;

public class EnvelopeChunkingTest : Test
{
    public EnvelopeChunkingTest(ITestOutputHelper output) : base(output)
    {
    }

    [Fact]
    public void ShouldSplitEnvelopeIntoChunkedReaders()
    {
        const string xml = @"<Envelope>
  <Entry id=""1""><Name>Alpha</Name></Entry>
  <Entry id=""2""><Name>Beta</Name></Entry>
  <Entry id=""3""><Name>Gamma</Name></Entry>
</Envelope>";

        using var reader = XmlReader.Create(new StringReader(xml));
        var payloads = reader
            .Chunk(2, o => o.Indent = true)
            .Select(chunk =>
            {
                chunk.MoveToFirstElement();
                return chunk.ReadOuterXml();
            })
            .ToArray();

        TestOutput.WriteLines(payloads);

        Assert.Collection(payloads,
            first =>
            {
                Assert.Contains("id=\"1\"", first);
                Assert.Contains("id=\"2\"", first);
                Assert.DoesNotContain("id=\"3\"", first);
            },
            second =>
            {
                Assert.DoesNotContain("id=\"1\"", second);
                Assert.Contains("id=\"3\"", second);
            });
    }
}

Use this pattern when one upstream XML envelope has to be processed or queued in smaller batches. Chunk keeps each batch as valid XML, so downstream code can continue to work with XmlReader instead of custom string splitting.

Installation

dotnet add package Cuemon.Extensions.Xml

Usage guidance

Adopt Cuemon.Extensions.Xml when you already work with XmlReader, XmlWriter, streams, or Cuemon's XML serializer abstractions and want less boilerplate around batching, copying, sanitizing, parsing, or converter registration. If you only need straightforward XDocument, XmlDocument, or XmlSerializer flows, the built-in System.Xml APIs or the lower-level Cuemon.Xml package are usually the better fit.

Family packages