Click here to Skip to main content
15,919,434 members
Articles / Programming Languages / C#
Tip/Trick

Tools for Schema & Schematron Validation and Stylesheet Transformation

Rate me:
Please Sign up or sign in to vote.
1.00/5 (1 vote)
14 Feb 2021CPOL6 min read 5.8K   4   1
XML schema Schematron and stylesheet transformation
This article describes package tool to validate schema, validate Schematron and do stylesheet transformation.

1. Introduction

When working with the NHS projects, I need to deal with a large number of linked schemas and create a package to validate messages against that schema. The NuGet package I created called Messaging.Core. Though there are some resources related to the NHS project, overall, the code can be used for other domains of application as well.

2. How to Use Messaging.Core Package

For how to use Messaging.Core in the code, you can see the unit tests in Github. This article will describe the component in the package and how to use them. The Messaging.Core contains a number of artifacts:

2.1 Resource Resolver

Namespace: Messaging.Resolvers

The package has resolvers that can resolve resources from either an assembly or from a directory. The resource resolver is inherited from XmlUrlResolver, IResourceResolver. The IResourceResolver has a method with a signature, Stream GetResourceStream(string resourceName), which resolves a resource given its name. When working with resource resolvers, the resource name is assumed to have two parts: name and extension. There are two types of resource resolvers in Messaging.Core package.

2.1.1. EmbeddedResourceResolver

Signatures:

  • public EmbeddedResourceResolver(Assembly resourceAssembly = null)
  • public static EmbeddedResourceResolver Create(AssemblyType assemblyType)
  • public Stream GetResourceStream(string resourceName)
  • public object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)

As the name implied, this resource resolver locates a resource as an embedded resource in an assembly. The instance constructor takes an assembly as the optional argument, and it will default to the current assembly if the argument is null. The static constructor takes enumerated AssemblyType, which can have a value of:

  • AssemblyType.Caller, the assembly which calls Messaging.Core method. This value can be used for unit testing where the resources normally reside within the unit test project.
  • AssemblyType.Library, the Messaging.Core assembly itself. This can be used to resolve resources that reside on the Messaging.Core project.
  • AssemblyType.EntryHost, the host assembly which executes the code on runtime, like console or web app projects.

If you use this resource resolver, you can use either package 1-4 assembly to validate a message against a schema in those packages. For the EmbeddedResourceResolver, locates embedded resources in the assembly based on the resources name and ignoring the path.

GetResourceStream method is part of IResourceResolver and can be used to resolve a resource name to a content stream. The package provides an extension method GetText to convert the stream to string content. GetEntity method is part of XmlUrlResolver, and normally used by other methods using XmlUrlResolver such as for schema validation, and it is not recommended to use it directly.

2.1.2. DirectoryResourceResolver

Signatures:

  • public DirectoryResourceResolver(string path)
  • public Stream GetResourceStream(string resourceName)
  • public object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)

If you use this resource resolver, you can validate a message against schema in a directory. The constructor takes the directory path as an argument. In order to use DirectoryResourceResolver, you just need to put DMS schemas or any other schema in a directory and validate a message against that directory. The resolver will locate resources based on the resource name, it does not matter where you put the resource in the directory, as long as they are all unique in that directory. The last two methods are the same as those of AssemblyResourceResolver.

3.2. Stylesheet Transformer

Namespace: Messaging.Transformers

Signatures:

  • public StylesheetTransformer(ResourceResolver resolver = null)
  • public string Transform(string stylesheetXml, string inputXml)
  • public Stream TransformStream(Stream stylesheetStream, Stream inputXmlStream)

The constructor takes an optional resource resolver and is used to resolve stylesheet references. You don't need one if working with a single stylesheet without any references. It has two Transform methods and a TransformStream method.

The first Transform method takes a stylesheet XML and an input XML, and if there are references in the stylesheet XML, it uses the resource resolver passed in the constructor to resolve the resources. The second Transform method takes an enumerated stylesheet in the Messaging.Core and an input XML. The enumerated stylesheet is specific to NHS projects, and may not be useful for general usage.

The last method, TransformStream, takes stream instead of raw XML for both stylesheet and input XML. There is an extension method in the Messaging.Core that converts from raw XML into a stream called GetStream.

3.3. SchemaValidator

Namespace: Messaging.Validators

Signatures:

  • public SchemaValidator(ResourceResolver externalResolver)
  • public static SchemaValidator Create(Assembly externalAssembly)
  • public static SchemaValidator Create(string folder)
  • public Result Validate(string schemaName, string inputXml)
  • public Result Validate(Stream schemaStream, Stream inputXmlStream)

The schema validator has a constructor that takes a resource resolver and also two static constructors that take either a folder path (uses DirectoryResourceResolver) or an assembly (use EmbeddedResourceResolver).

The first Validate method takes a schema name and input XML. The schema name is resolved to a resource by the resource resolver passed in the constructor. The schema name is the name of the schema with or without an xsd extension, for example, it can be COCD_TP146045UK05Author2 or COCD_TP146045UK05Author2.xsd. If you have a single schema resource, you can convert it to a stream, e.g., using GetStream method, and use the second Validate method which takes a schema stream instead.

The return of Validate method is Result, which contains boolean Status, a string Description, and optionally an Exception.

3.4. SchematronValidator

Namespace: Messaging.Validators

Signatures:

  • public SchematronValidator(string schematronContent, bool convertToIsoNamespace = false)
  • public SchematronValidator(Stream schematronStream)
  • public static SchematronValidator Create(SchematronDocument schematronDocument)
  • public Result Validate(string inputXml)
  • public Result Validate(Stream inputStream)

SchematronValidator is an iso Schematron compliant validator. It has two instance constructor and one static constructor. The first instance constructor takes a Schematron content XML and a flag convertToIsoNamespace. The flag is used to indicate whether or not to convert the namespace in the Schematron content if the old XML namespace is found. The old Schematron content has an XML namespace 'http://www.ascc.net/xml/schematron', while the new Schematron content has an XML namespace of 'http://purl.oclc.org/dsdl/schematron'. Without the conversion, the validator will fail to validate a message if the old Schematron content is passed in the constructor. The static constructor takes an enumerated Schematron content which is located in the Messaging.Core assembly. The enumerated Schematron is NHS specific and may not be useful for general usage.

In order to validate an XML message against the Schematron content, use Validate method. It has two variants. The first variant takes a raw XML while the other takes a stream.

As a side note, the Messaging.Core can be used with any other domain applications. It can be used with any complex schema or a simple one. In order to use a directory resource resolver, you can just put all your schema in a directory, and create a DirectoryResourceResolver object passing the directory to the constructor, and then you are on your way to use validators and transformer in Messaging.Core.

Alternatively, you can put all your schema in an assembly as embedded resources and create an EmbeddedResourceResolver object by passing the assembly in the constructor. Alternatively, you can implement your own resolver, implementing ResourceResolver.

History

  • 15th February, 2021: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) EMIS
United Kingdom United Kingdom
(You can visit my blog in

Comments and Discussions

 
Questionxslt2 support Pin
Philippe Demerliac25-Jul-22 5:00
Philippe Demerliac25-Jul-22 5:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.