ZUGFeRD-csharp icon indicating copy to clipboard operation
ZUGFeRD-csharp copied to clipboard

ApplicableHeaderTradeDelivery empty element

Open danvy opened this issue 2 weeks ago • 2 comments

The produced XML might contain an empty ApplicableHeaderTradeDelivery element. Empty elements generates an error official validation processes.

As this is not the first time empty elements appear, I decided to create a workaround.

using System.Xml;
using System.Xml.Linq;

public static class XmlStreamProcessor
{
    public static Stream RemoveEmptyElements(Stream inputStream)
    {
        if (inputStream == null)
            throw new ArgumentNullException(nameof(inputStream));
        // Load the XML from the input stream
        var doc = XDocument.Load(inputStream);
        // Remove all empty elements recursively
        RemoveEmptyElementsRecursive(doc.Root);
        // Create a new memory stream for the output
        var outputStream = new MemoryStream();
        // Save the modified XML to the output stream
        using (var writer = XmlWriter.Create(outputStream, new XmlWriterSettings
        {
            Indent = true,
            OmitXmlDeclaration = false,
            CloseOutput = false
        }))
        {
            doc.Save(writer);
        }
        // Reset the stream position to the beginning
        outputStream.Position = 0;   
        return outputStream;
    }
    private static void RemoveEmptyElementsRecursive(XElement? element)
    {
        if (element == null)
            return;
        // Process children first (bottom-up approach)
        var children = element.Elements().ToList();
        foreach (var child in children)
        {
            RemoveEmptyElementsRecursive(child);
        }
        // Remove child elements that are empty
        element.Elements()
            .Where(e => IsEmpty(e))
            .Remove();
    }
    private static bool IsEmpty(XElement element)
    {
        // An element is considered empty if:
        // 1. It has no child elements
        // 2. It has no text content (or only whitespace)
        // 3. It has no attributes
        return !element.HasElements &&
               !element.HasAttributes &&
               string.IsNullOrWhiteSpace(element.Value);
    }
}

// Example usage:
// using var inputStream = File.OpenRead("input.xml");
// using var outputStream = XmlStreamProcessor.RemoveEmptyElements(inputStream);
// using var fileOutput = File.Create("output.xml");
// outputStream.CopyTo(fileOutput);

The writers might be fixed for every single element output or a new InvoiceFormatOptions.RemoveEmptyElements might be introduced to ensure for once that not a single empty element breaks the conformance. What do you prefer ?

danvy avatar Dec 21 '25 18:12 danvy