0

All I have is: "You can call SetInvalidityHandler(IInvalidityHandler inHandler). This will cause each validity error to be reported to your supplied handler. The error is reported by way of a (poorly named) StaticError object. This wraps a Java ValidationFailure object."
I have tried: (yes, it is vb, c# responses are also fine)

Delegate Sub ValidationCallBack(errH As Saxon.Api.IInvalidityHandler)
Dim IIH As Saxon.Api.IInvalidityHandler    'very suss on this line

then a sub;

Sub ValidationCallBackEvent(errH As Saxon.Api.IInvalidityHandler)
    dim k as integer
    k=0 'F9 here
End Sub

then a sub containing;

Dim deleg As New ValidationCallBack(AddressOf ValidationCallBackEvent)

Dim processor = New Processor(True)
Dim sXsdPathUri As String = "c:\temp\the.xsd"
Dim sXmlPathUri As String = "c:\temp\the.xml"

processor.SetProperty("http://saxon.sf.net/feature/timing", "true")
processor.SetProperty("http://saxon.sf.net/feature/validation-warnings", "false") 

Dim manager As SchemaManager = processor.SchemaManager     
Dim schemaUri As System.Uri
schemaUri = New System.Uri(sXsdPathUri)

manager.Compile(schemaUri)

Dim validator As SchemaValidator = manager.NewSchemaValidator
Dim settings As System.Xml.XmlReaderSettings = New System.Xml.XmlReaderSettings
settings.DtdProcessing = System.Xml.DtdProcessing.Ignore
Dim inputFileName As String = New Uri(sXmlPathUri).ToString()
Dim xmlReader As System.Xml.XmlReader = System.Xml.XmlReader.Create(inputFileName, settings)
validator.SetSource(xmlReader)

validator.SetInvalidityHandler(IIH)  'suss; but it needs a Saxon.Api.IInvalidityHandler..
validator.Run()
Try
    validator.Run()
    sResult = "Valid!!"
Catch ex As Exception
    Dim err As StaticError
    For Each err In validator.ErrorList 'still goes here

It's not erroring but neither is the ValidationCallBackEvent being raised so clearly my plumbing is incorrect.

Any ideas? thanks!

walbury
  • 68
  • 5
  • My understanding is that http://saxonica.com/html/documentation/dotnetdoc/Saxon/Api/IInvalidityHandler.html is an interface, so you need to write a class implementing that interface (https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/interfaces/#implementing-interfaces), then you can instantiate the class and pass the instance created to `SetInvalidityHandler`.and Saxon will call the methods declared in the interface and your class can handle the data passed in. – Martin Honnen Jul 17 '18 at 09:35
  • Yes, correct. It was more the "how" that is done that I was a bit stuck on.. it's been many a year since I did something similar when importing type libs into VB6. Saxon support kindly posted a c# sample which was sufficient to get me over the line. – walbury Jul 28 '18 at 06:44

1 Answers1

0

Saxon support kindly posted a C# example;

public void TestInvalidityHandler()
    {
        XmlReader xsd = XmlReader.Create(Path.GetFullPath(ConfigTest.DATA_DIR + "books.xsd"));
        XmlReader source_xml = XmlReader.Create(new StringReader("<?xml version='1.0'?><request><user_name>ed</user_name><password>sdsd</password><date1>a2009-01-01</date1><date2>b2009-01-01</date2></request>"));
        UriBuilder ub = new UriBuilder();
        ub.Scheme = "file";
        ub.Host = "";
        ub.Path = @"C:\work\tests\";
        Uri baseUri = ub.Uri;

        Processor saxon = new Processor(true);

        SchemaManager manager = saxon.SchemaManager;
        manager.ErrorList = new ArrayList();
        manager.XsdVersion = "1.0";
        try
        {
            DocumentBuilder builder = saxon.NewDocumentBuilder();
            builder.BaseUri = new Uri("http://example.com");
            XdmNode xsdNode = builder.Build(xsd);
            manager.Compile(xsdNode);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Schema compilation failed with " + manager.ErrorList.Count + " errors");
            String errors = "";
            foreach (StaticError error in manager.ErrorList)
            {
                Console.WriteLine("At line " + error.LineNumber + ": " + error.Message);
                errors += error.Message + "\n";
            }
            Assert.Fail("Failed in compile of xsd "+ errors);

        }
        Saxon.Api.SchemaValidator validator = manager.NewSchemaValidator();
        validator.SetInvalidityHandler(new MyInvalidaityHandler());
        validator.SetSource(source_xml);
        try
        {
            validator.Run();
            Assert.True(true);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.StackTrace);
            Assert.Fail(ex.Message);
        }
    }

    public class MyInvalidaityHandler : IInvalidityHandler
    {
        public XdmValue endReporting()
        {
            return currentNode; // this could be the entire  constructedreport
        }
        public void reportInvalidity(StaticError i)
        {
            //TODO - Do something here. Maybe write to a file or throw an exception 
        }
        public void startReporting(string systemId)
        {
            // no action, but can do setup of file
        }
    }
}

This was enough for me to get a working VB.net version;

 Function TestInvalidityHandler() As String
    Dim sReturn As String
    Dim processor = New Processor(True)
    Dim sXmlPathUri As String
    Dim sXsdPathUri As String
    sXsdPathUri = "K:\SamplesFinal_ALL\IncludesImports\ALL\DotNetParserErrorTest\orderProd_YYNY_QQ.xsd"
    sXmlPathUri = "K:\SamplesFinal_ALL\IncludesImports\ALL\DotNetParserErrorTest\SampleFile_YYNY_QQ_dotNetValid.xml"
    processor.SetProperty("http://saxon.sf.net/feature/timing", "true")
    processor.SetProperty("http://saxon.sf.net/feature/validation-warnings", "false") ' //Set to true to suppress the exception

    Dim manager As SchemaManager = processor.SchemaManager
    manager.XsdVersion = "1.1"

    Dim schemaUri As System.Uri
    schemaUri = New System.Uri(sXsdPathUri)
    manager.Compile(schemaUri)                  'error handling removed for the moment..
    Dim validator As SchemaValidator = manager.NewSchemaValidator
    validator.SetInvalidityHandler(New MyInvalidityHandler())
    'use dot net objects;
    Dim settings As System.Xml.XmlReaderSettings = New System.Xml.XmlReaderSettings
    settings.DtdProcessing = System.Xml.DtdProcessing.Ignore
    Dim inputFileName As String = New Uri(sXmlPathUri).ToString()
    Dim xmlReader As System.Xml.XmlReader = System.Xml.XmlReader.Create(inputFileName, settings)
    validator.SetSource(xmlReader)
    Try
        validator.Run()
        sReturn = "OK"
    Catch ex As Exception
        sReturn = ex.Message
    End Try
    Return sReturn

End Function

Public Class MyInvalidityHandler

    Implements Saxon.Api.IInvalidityHandler

    Public Sub reportInvalidity(ByVal se As StaticError) Implements Saxon.Api.IInvalidityHandler.reportInvalidity
        'Get path etc from se.Message
    End Sub

    Public Sub startReporting(ByVal systemId As String) Implements Saxon.Api.IInvalidityHandler.startReporting
        'started
    End Sub

    Public Function endReporting() As XdmValue Implements Saxon.Api.IInvalidityHandler.endReporting
        Dim currentNode As XdmValue
        Return currentNode 'what's in xdm?
    End Function

End Class

so no need of delegate or interface, in fact almost obvious now I've got the answer. Final note; thanks to Steven Doggart's answer to Error that I must implement a function in a class even though function is defined. The Class 'MyInvalidityHandler' must implement 'Function endReporting() As XdmValue' for interface 'Saxon.Api.IInvalidityHandler' error was a bit of a stmbling block for a while and the main point of difference between C# and VB.net in this scenario.

walbury
  • 68
  • 5