SEPA is coming and people have been asking how can I check if this pain file is valid. In this post I will demonstrate how we can transform an XML file to HTML and include any XSD validation exceptions into the mix.
The technique described here is general purpose i.e. its not limited to PAIN.008 and PAIN.002 files, these XML files just seem to be in fashion.
Internet Explorer has a clever trick up its sleeve when it comes to rendering XML files. It basically converts them on the fly using an XSLT style-sheet called defaultss.xsl. This style-sheet is packaged inside the MSXML3.dll file e.g. res://msxml3.dll/xml/defaultss.xsl will display the style sheet in Internet Explorer. The flavour of XSL contained in this stylesheet is based on a working draft but a bit of googling will find a version based on an XSL recommendation.
With some minor modification I’ve leveraged this stylesheet to render the XML file along with the XSD validation issues. The file was a bit long to include in the post so I’ve made it available as a gist.
If you look at the XSL file you can see I’ve added a couple of new templates to match four new processing instructions.
- schemaSummary
- schemaValid
- schemaInvalid
- error
This new processing instructions are added to the SAX event stream by a specialised XMLFilter implementation.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package ie.robb.sax.helpers; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.XMLFilterImpl; public class ErrorInjectionFilter extends XMLFilterImpl { String schemaIdentifier; int errorCount = 0; public ErrorInjectionFilter(String schemaIdentifier) { this.schemaIdentifier = schemaIdentifier; } public void startDocument() throws SAXException { super.startDocument(); processingInstruction("schemaSummary", schemaIdentifier); } @Override public void endDocument() throws SAXException { processingInstruction("schema" + (errorCount > 0 ? "Invalid" : "Valid"), String.valueOf(errorCount)); super.endDocument(); } public void error(SAXParseException exception) throws SAXException { getParent().getContentHandler().processingInstruction("error", exception.getMessage()); errorCount ++; } public void fatalError(SAXParseException exception) throws SAXException { throw exception; } public void warning(SAXParseException exception) throws SAXException { error(exception); } } |
And here is a quick JUnit test to run transform a sample file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
@Test public void test() throws Throwable { Schema iso20022 = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI) .newSchema(this.getClass() .getResource("/pain.008.001.03.xsd")); SAXParserFactory pf = SAXParserFactory.newInstance(); SAXTransformerFactory sf = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); pf.setSchema(iso20022); pf.setNamespaceAware(true); XMLFilter xslFilter = sf.newXMLFilter(new StreamSource(this.getClass().getResourceAsStream("/defaultss.xsl"))); SAXParser parser = pf.newSAXParser(); Transformer transformer = sf.newTransformer(); ErrorInjectionFilter filter = new ErrorInjectionFilter("iso20022/pain.008.001.03"); parser.getXMLReader().setErrorHandler(filter); filter.setParent(parser.getXMLReader()); xslFilter.setParent(filter); transformer.transform(new SAXSource(xslFilter, new InputSource(this.getClass() .getResourceAsStream("/pain.008.001.03.xml"))), new StreamResult(new FileOutputStream("pain.008.001.03.html"))); } |
I downloaded a sample PAIN.008 file from the ISO20022 website and added one or two typo’s and ran it through the test case. The results looks like
Leave a Reply