Using SAXON 9.5 (nuget) with Schematron
Asked Answered
D

2

4

I am running this code:

        string path = AppDomain.CurrentDomain.BaseDirectory;

        // Uri schemaUri = new Uri(@"file:\\" + path + @"\sch\patient.sch");
        Uri totransformEE = new Uri(@"file:\\" + path + @"\po\po-schema.sch");
        Uri transformER = new Uri(@"file:\\" + path + @"\xsl\conformance1-5.xsl");

        ///////////////////////////////
        // Crate Schemtron xslt to be applied
        ///////////////////////////////
        // Create a Processor instance.
        Processor processor = new Processor();

        // Load the source document
        XdmNode input = processor.NewDocumentBuilder().Build(totransformEE);

        // Create a transformer for the stylesheet.
        XsltTransformer transformer = processor.NewXsltCompiler().Compile(transformER).Load();

        // Set the root node of the source document to be the initial context node
        transformer.InitialContextNode = input;

        // Create a serializer
        Serializer serializer = new Serializer();
        MemoryStream st = new MemoryStream();
        serializer.SetOutputStream(st);

        // Transform the source XML to System.out.
        transformer.Run(serializer);

        st.Position = 0;
        System.IO.StreamReader rd = new System.IO.StreamReader(st);
        string xsltSchematronStylesheet = rd.ReadToEnd();

        System.Diagnostics.Debug.WriteLine(xsltSchematronStylesheet);

        // Load the source document
        Uri transformEE2 = new Uri(@"file:\\" + path + @"\po\po-bad.xml");

        var documentbuilder2 = processor.NewDocumentBuilder();
        XdmNode input2 = documentbuilder2.Build(transformEE2);

        ////// Create a transformer for the stylesheet.
        StringReader sr2 = new StringReader(xsltSchematronStylesheet);
        XsltTransformer transformer2 = processor.NewXsltCompiler().Compile(sr2).Load();

        // Set the root node of the source document to be the initial context node
        transformer2.InitialContextNode = input2;

        // Create a serializer
        Serializer serializer2 = new Serializer();
        MemoryStream st2 = new MemoryStream();
        serializer.SetOutputStream(st2);

        transformer2.MessageListener = new MyMessageListener();
        // Transform the source XML to System.out.
        transformer2.Run(serializer2);

        st2.Position = 0;
        System.IO.StreamReader rd2 = new System.IO.StreamReader(st2);
        string xsltSchematronResult = rd2.ReadToEnd();
        System.Diagnostics.Debug.WriteLine(xsltSchematronResult);

I get what appears to be an XSLT file when examining xsltSchematronStylesheet. However the stream at the end st2 has 0 length. Also, MyMessageListener.Message receives no calls (I used a break point).

I am not sure if I have bad code, bad sample files, etc. I believe my sample files are correct, but maybe I have bad ones or am missing some.

Does anyone know why no data is returned to the stream st2. If not can you direct me to a good simple sample that has all the files and works?

Dharna answered 27/2, 2014 at 5:13 Comment(5)
Well, for starters, those backslashes look suspicious. URIs always contain forward slashes, never backslashes.Mancino
Try calling Close() on the MemoryStream. Perhaps setting Position=0 deletes the existing contents. (I'm no expert here, the MemoryStream class has always confused me.)Mancino
I am starting to think my xsl and/or sch and/or xml files are defective in some way. I discovered "iso-schematron-xslt2" which use the "purl.oclc.org/dsdl/schematron" namespace referred to in [link]#16943439. However I get the same behavior using these files. Unfortunately the iso-schematron-xslt2 file set do not include a known good sample of sch and xml to test. Can anyone point me to such a sample ?Dharna
You could use XML ValidatorBuddy (during the trial period) to see if your Schematron schema can be transformed to a stylesheet at all. The tool has a command to get the XSLT from any Schematron schema. In addition it lets you specify which stylesheet should be used for the transformation (comes installed with the stylesheet for the purl.oclc.org/dsdl/schematron ISO namespace you mentioned) and uses Saxon for the transformation.Binaural
I tried XML ValidatorBuddy(XVB) on two very simple files (xml, sch) and it worked proving the files work - at least using the built in java implementation of Saxon-HE. I used XVB to create a stylesheet from sch and used that stylesheet to fill the variable 'xsltSchematronStylesheet'. I then ran the transform on the xml file and still ended up with a null in the stream.Dharna
D
9

My real underlying problem was finding simple complete sample code to do Schematron in .Net. So for the next guy here is the sample I was looking for. I have tried to make this as complete as possible. If I missed something, leave a comment.

  1. Create a unit test project
  2. Run the Nuget Command
  3. Download the Schematron files
  4. Use the included classes and sch, xml files.
  5. Run the test program

Nuget Saxon Commandline:

Install-Package Saxon-HE 

Download Up to date Schematron Files http://www.schematron.com/tmp/iso-schematron-xslt2.zip

UnitTest:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;

namespace SOAPonFHIR.Test
{
    [TestClass]
    public class Schematron
    {
        [TestMethod]
        public void XSLT_SAXON_Simple_Schematron2()
        {

            ///////////////////////////////
            // Transform original Schemtron  
            ///////////////////////////////
            string path = AppDomain.CurrentDomain.BaseDirectory;

            Uri schematron = new Uri(@"file:\\" + path + @"\simple\input.sch");
            Uri schematronxsl = new Uri(@"file:\\" + path + @"\xsl_2.0\iso_svrl_for_xslt2.xsl");

            Stream schematrontransform = new Test.XSLTransform().Transform(schematron, schematronxsl);

            ///////////////////////////////
            // Apply Schemtron xslt 
            ///////////////////////////////
            FileStream xmlstream = new FileStream(path + @"\simple\input.xml", FileMode.Open, FileAccess.Read, FileShare.Read);
            Stream results = new Test.XSLTransform().Transform(xmlstream, schematrontransform);

            System.Diagnostics.Debug.WriteLine("RESULTS");
            results.Position = 0;
            System.IO.StreamReader rd2 = new System.IO.StreamReader(results);
            string xsltSchematronResult = rd2.ReadToEnd();
            System.Diagnostics.Debug.WriteLine(xsltSchematronResult);

        }
    }
}

Transform Class:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using Saxon.Api;
using System.IO;
using System.Xml.Schema;
using System.Collections.Generic;

namespace SOAPonFHIR.Test
{
    public class XSLTransform
    {
        public Stream Transform(Uri xmluri, Uri xsluri)
        {


            // Create a Processor instance.
            Processor processor = new Processor();

            // Load the source document
            XdmNode input = processor.NewDocumentBuilder().Build(xmluri);

            // Create a transformer for the stylesheet.
            var compiler = processor.NewXsltCompiler();
            compiler.ErrorList = new System.Collections.Generic.List<Exception>();

            XsltTransformer transformer = compiler.Compile(xsluri).Load();

            if (compiler.ErrorList.Count != 0)
                throw new Exception("Exception loading xsl!");

            // Set the root node of the source document to be the initial context node
            transformer.InitialContextNode = input;

            // Create a serializer
            Serializer serializer = new Serializer();
            MemoryStream results = new MemoryStream();
            serializer.SetOutputStream(results);

            // Transform the source XML to System.out.
            transformer.Run(serializer);

            //get the string
            results.Position = 0;
            return results;


        }

        public System.IO.Stream Transform(System.IO.Stream xmlstream, System.IO.Stream xslstream)
        {

            // Create a Processor instance.
            Processor processor = new Processor();

            // Load the source document
            var documentbuilder = processor.NewDocumentBuilder();
            documentbuilder.BaseUri = new Uri("file://c:/" );
            XdmNode input = documentbuilder.Build(xmlstream);

            // Create a transformer for the stylesheet.
            var compiler = processor.NewXsltCompiler();
            compiler.ErrorList = new System.Collections.Generic.List<Exception>();
            compiler.XmlResolver = new XmlUrlResolver();
            XsltTransformer transformer = compiler.Compile(xslstream).Load();

            if (compiler.ErrorList.Count != 0)
                throw new Exception("Exception loading xsl!");

            // Set the root node of the source document to be the initial context node
            transformer.InitialContextNode = input;

            // Create a serializer
            Serializer serializer = new Serializer();
            MemoryStream results = new MemoryStream();
            serializer.SetOutputStream(results);

            // Transform the source XML to System.out.
            transformer.Run(serializer);

            //get the string
            results.Position = 0;
            return results;


        }

    }
}

Schematron File

<?xml version="1.0" encoding="utf-8"?>
<iso:schema
  xmlns="http://purl.oclc.org/dsdl/schematron" 
  xmlns:iso="http://purl.oclc.org/dsdl/schematron"
  xmlns:dp="http://www.dpawson.co.uk/ns#"
  queryBinding='xslt2'
  schemaVersion='ISO19757-3'>

  <iso:title>Test ISO schematron file. Introduction mode</iso:title>
  <iso:ns prefix='dp' uri='http://www.dpawson.co.uk/ns#'/> 

  <iso:pattern>
    <iso:rule context="chapter">

      <iso:assert
         test="title">A chapter should have a title</iso:assert>  
    </iso:rule>
  </iso:pattern>


</iso:schema>

XML File

<?xml version="1.0" encoding="utf-8" ?>
<doc>
  <chapter id="c1">
    <title>chapter title</title>  
    <para>Chapter content</para>
  </chapter>

  <chapter id="c2">
    <title>chapter 2 title</title>
    <para>Content</para>           
  </chapter>

  <chapter id="c3">
    <title>Title</title>
    <para>Chapter 3 content</para>
  </chapter>
</doc>

Results:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<svrl:schematron-output xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
                        xmlns:xs="http://www.w3.org/2001/XMLSchema"
                        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                        xmlns:saxon="http://saxon.sf.net/"
                        xmlns:schold="http://www.ascc.net/xml/schematron"
                        xmlns:iso="http://purl.oclc.org/dsdl/schematron"
                        xmlns:xhtml="http://www.w3.org/1999/xhtml"
                        xmlns:dp="http://www.dpawson.co.uk/ns#"
                        title="Test ISO schematron file. Introduction mode"
                        schemaVersion="ISO19757-3"><!--   
           
           
         -->
   <svrl:ns-prefix-in-attribute-values uri="http://www.dpawson.co.uk/ns#" prefix="dp"/>
   <svrl:active-pattern document="file:///c:/"/>
   <svrl:fired-rule context="chapter"/>
   <svrl:fired-rule context="chapter"/>
   <svrl:fired-rule context="chapter"/>
</svrl:schematron-output>
Dharna answered 28/2, 2014 at 23:42 Comment(2)
An update to the code of the Transform class: Serializers are now created using Processor.NewSerializer() instead of the ctorClements
@Dharna you really should push the code from your one-drive share to github. Indeed very helpful!Curtsy
D
2

Resolution:

serializer.SetOutputStream(st2);

should be

serializer2.SetOutputStream(st2);
Dharna answered 28/2, 2014 at 22:35 Comment(2)
I added a complete demo solution at: onedrive.live.com/…Dharna
+ adamın dibisin dibi.Lobelia

© 2022 - 2024 — McMap. All rights reserved.