Validate your EN 16931 eInvoices in .NET with the Lombiq eInvoice Validator
Would you like to validate EN 16931 XML eInvoices in your .NET application? Then, this is your lucky day, we have just released an open-source .NET library specifically for this.
What does the Lombiq eInvoice Validator do?
The Lombiq eInvoice Validator checks if the given XML is valid against the latest release of EN 16931 artifacts (v1.3.14.1 as of writing this), directly from the official eInvoicing-EN16931 repository. We currently support UBL 2.1 and CII (D16B) eInvoice validation.
How does it work?
First things first, if you run the full validation, we detect the eInvoice format (UBL or CII), then we use the correct schema files to check if the structure is valid. Then we validate the data itself with the schematron files.
Schema validation
Schema validation checks the structure of the XML. We use the System.Xml
built-in namespace. We are loading the format-specific .xsd
files into an XmlReaderSettings
and we are also adding a ValidationEventHandler
to it. Then we read through the XML with an XmlReader
. On each validation event, the error message is collected and will be returned in the result object. You can see it in detail in the SchemaValidationServices file.
Schematron validation
Schematron validation is not that easy in .NET, because the .XSLT
or .SCH
files that are used to validate with XML transformation contain XPath 2.0+ definitions. And in .NET, only XPath 1.0 is supported natively. So, we looked into possible solutions, and SaxonJS 2 in Node.js seemed to be the best for our needs.
SaxonJS 2 is free of charge, but not open-source. The code is the intellectual property of Saxonica, except for the open-source components listed in the SaxonJS documentation.
How do we run a Node.js module in .NET? We use a Node.js wrapper called Jering.Javascript.NodeJS. It enables you to invoke JavaScript in Node.js, from C#. It also takes care of handling these Node.js processes and multi-processing.
This SaxonJS library contains xslt3
command line tool, which helps to convert .XSLT
files into .sef.json
files, which are used by SaxonJS to do the transformation. This transformation is our validation. Then we read this transformed file to get all the warnings and errors. If you are interested in how this is done in code, feel free to check the SchematronValidationService.
How can you use it?
The following samples don’t include the common setup required before using the validation methods. For complete examples and setup instructions, check out our sample project: Lombiq.EInvoiceValidator.Sample.
You can either use it as a NuGet package, or from source as a submodule. As described above, you will need Node.js installed from here, the LTS version is recommended.
You can perform full validation, or validate only schema or only schematron.
Full validation
You can use the implementation of the IInvoiceValidationService
by calling the ValidateInvoiceAsync
method. The parameter can be a string, which is the XML, or an XML stream. The result will be an InvoiceValidationResult object, that contains the Schema and Schematron results.
// DI in constructor the IInvoiceValidationService or get it from the service provider.
var invoiceValidationService = serviceProvider.GetRequiredService<IInvoiceValidationService>();
// For XML string.
var validationResult = await invoiceValidationService.ValidateInvoiceAsync(xmlString);
// For XML stream.
var validationResult = await invoiceValidationService.ValidateInvoiceAsync(xmlStream);
if (validationResult.Successful)
{
// Invoice is valid.
}
if (validationResult.HasWarnings)
{
// Handle warnings.
}
else
{
// Access validationResult.SchemaValidationResult and validationResult.SchematronValidationResult for details.
}
Detect XML format
As mentioned before we detect the eInvoice XML format automatically, whether it is UBL or CII, when you call the full validation method. But you can also do it manually by calling IInvoiceValidationService.DetectFormatAsync
:
// DI in constructor the IInvoiceValidationService or get it from the service provider.
var invoiceValidationService = serviceProvider.GetRequiredService<IInvoiceValidationService>();
// For XML string.
var format = await invoiceValidationService.DetectFormatAsync(xmlString);
// For XML stream.
var format = await invoiceValidationService.DetectFormatAsync(xmlStream);
if (format == InvoiceFormat.UBL)
{
// Handle UBL invoice.
}
else if (format == InvoiceFormat.CII)
{
// Handle CII invoice.
}
else
{
// Unknown or unsupported format.
}
Running Schema validation separately
Validate an XML invoice against the XSD schema only with the ISchemaValidationService
:
// DI in constructor the ISchemaValidationService or get it from the service provider.
var schemaValidationService = serviceProvider.GetRequiredService<ISchemaValidationService>();
// For string XML.
var schemaResult = await schemaValidationService.ValidateXmlAgainstSchemaAsync(
xmlString,
InvoiceFormat.CII);
// Or using stream.
var schemaResult = await schemaValidationService.ValidateXmlAgainstSchemaAsync(
xmlStream,
InvoiceFormat.CII);
if (schemaResult.ErrorMessages.Any())
{
// Handle schema validation errors.
}
To get started, visit the Lombiq eInvoice Validator GitHub repository for more information and access to the source code.
Integrate into your system
That’s it! Validating eInvoices is a simple method call away.
If you have any questions or need assistance integrating the validator into your .NET or Orchard Core applications, feel free to reach out to us.