ZUGFeRD-csharp
ZUGFeRD-csharp copied to clipboard
ApplicableHeaderTradeDelivery empty element
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 ?