XML validation with Schematron

531 Views Asked by At

Do you know of any C#/NET libraries to validate an XML file with Schematron.

I searched but couldn't find anything.

Thanks for your help.

Anthony

I tried to use the Schematron.NET library but the validation doesn't work.

I tried this code:

try
            {                       
                using (var xrXML = XmlReader.Create("xmlData.xml"))                                
                {
                    using (var xrSch = XmlReader.Create("schematron.sch"))
                    {
                        Validator vld = new Validator();
                        var schema = new Schema();
                        schema.Load(xrSch);
                        vld.AddSchema(schema);
                        var path = vld.Validate(xrXML);
                        vld.ValidateSchematron(path);                          
                    }
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

Even inserting an invalid xml does not return an error.

1

There are 1 best solutions below

1
Martin Honnen On

One established way to perform Schematron validation is to use XSLT to compile/transpile the Schematron schema to an intermediary XSLT which can then be used to validate the input XML instance document, producing an SVRL output. The established, modern XSLT 2/3 implementation of Schematron is called Schxslt, it is available on Github at https://github.com/schxslt/schxslt, the current release is 1.9.5 https://github.com/schxslt/schxslt/releases/tag/v1.9.5.

In the .NET world, to use the XSLT 2/3 version Schxslt, you need to use an XSLT 2.0 or 3.0 processor like Saxon, available for the .NET framework on NuGet by Saxonica at https://www.nuget.org/packages/Saxon-HE and for .NET 6/7 (aka .NET Core) as the commercial SaxonCS https://www.nuget.org/packages/SaxonCS and (in an open-source, IKVM cross-compiled version (disclaimer: I created that package)) with the NuGet package https://www.nuget.org/packages/SaxonHE11s9apiExtensions.

Using Saxon, you would use the Schxslt XSLT files to transpile your Schematron schema itself to an intermediary XSLT that you then run on the instance XML to validate it. A command line sample (targetting both .NET framework 4.8 as well as .NET 6) using the package https://www.nuget.org/packages/SaxonHE11s9apiExtensions and also pulling Schxslt directly from Maven is as follows:

using System;
using net.sf.saxon.s9api;
using net.liberty_development.SaxonHE11s9apiExtensions;
using System.Reflection;
using System.Diagnostics;
using net.sf.saxon.lib;
using System.IO;

namespace SchematronSchxsltSaxonHE11Net
{
    internal class Program
    {
        static string schxsltSvrlXsltResource = "/xslt/2.0/pipeline-for-svrl.xsl";

        static void Main(string[] args)
        {
            Console.WriteLine($"Schematron Schxslt Validator using Schxslt 1.9.5 and Saxon HE 11.5 under {Environment.Version} {Environment.OSVersion}");

            if (args.Length != 2)
            {
                Console.WriteLine($"Usage: SchematronSchxsltSaxonHE11Net schema.sch input.xml");
                return;
            }

            var stopWatch = new Stopwatch();
            stopWatch.Start();
            // load Schxslt assembly
            var schxsltAssembly = Assembly.Load("schxslt");
            ikvm.runtime.Startup.addBootClassPathAssembly(schxsltAssembly);

            // force loading of updated xmlresolver, not necessary with Saxon 11.5
            //ikvm.runtime.Startup.addBootClassPathAssembly(Assembly.Load("org.xmlresolver.xmlresolver"));
            //ikvm.runtime.Startup.addBootClassPathAssembly(Assembly.Load("org.xmlresolver.xmlresolver_data"));

            var processor = new Processor(false);

            var xsltCompiler = processor.newXsltCompiler();

            var jarResolver = new JarResolver();

            xsltCompiler.setResourceResolver(jarResolver);

            var compiledSchxslt = xsltCompiler.compile(jarResolver.resolve(new ResourceRequest() { baseUri = "schxslt", relativeUri = schxsltSvrlXsltResource })).load30();

            var compiledSchematron = new XdmDestination();
            compiledSchematron.setBaseURI(new Uri(new FileInfo(args[0]).FullName).ToURI());

            compiledSchxslt.Transform(new FileInfo(args[0]), compiledSchematron);

            var xsltCompiler2 = processor.newXsltCompiler();

            var schematronValidator = xsltCompiler2.compile(compiledSchematron.getXdmNode().asSource()).load30();

            var svrlResult = new XdmDestination();

            schematronValidator.Transform(new FileInfo(args[1]), svrlResult);

            var valid = processor.newXPathCompiler().evaluateSingle("not((/Q{http://purl.oclc.org/dsdl/svrl}schematron-output!(Q{http://purl.oclc.org/dsdl/svrl}failed-assert , Q{http://purl.oclc.org/dsdl/svrl}successful-report)))", svrlResult.getXdmNode()).getUnderlyingValue().effectiveBooleanValue();

            Console.WriteLine($"XML document {args[1]} is {(valid ? "" : "not ")}valid against Schematron schema {args[0]}.");

            if (!valid)
            {
                Console.WriteLine($"{Environment.NewLine}Validation report:{Environment.NewLine}{svrlResult.getXdmNode()}");
            }

            stopWatch.Stop();

            Console.WriteLine($"Elapsed time: {stopWatch.Elapsed}");
        }
    }
}

A sample project is at https://github.com/martin-honnen/SchematronSchxsltSaxonHE11Net. It has the used JarResolver to load the Schxslt files as a jar resource in https://github.com/martin-honnen/SchematronSchxsltSaxonHE11Net/blob/master/SchematronSchxsltSaxonHE11Net/JarResolver.cs.

Similar code can of course be written using Saxonica's Saxon-HE NuGet package for the .NET framework or Saxonica's commercial SaxonCS for .NET 6/7, see the GitHub repository https://github.com/martin-honnen/SchematronSchxsltSaxonCSValidator for an example .NET 6 console app using SaxonCS and Schxslt.

In the end you need an XSLT 2/3 processor to perform the Schematron validation, if you use an XSLT based implementation like Schxslt.