Validating an XML file against a schema with Natural and Java

Although Natural provides (very basic) functionality to parse and load an XML file, I could not find a way to validate XML against a schema. So I wrote a small Java program that does the validation and can be called from Natural (on Linux) via a User Exit.

Here is the Natural code for subprogram XMLVALID. It validates an XML file against a given schema using User Exit USR1052N (call a shell command) redirecting the output to a temp file. If an error occurred it reads the temp file and returns the error message. It uses quite a few hard coded paths you may need to change on your system.

DEFINE DATA
*
PARAMETER USING XMLVALP
*
LOCAL USING XMLVALC
*
LOCAL
01 USR1052L
  02 OS-COMMAND (A253)
  02 RESPONSE   (I04)
*
01 #TEMPFILE (A) DYNAMIC
*
01 #WORK (A1000)
*
01 #DEFAULT-SCHEMA-PATH (A) DYNAMIC CONST <'/home/XML/'>
01 #INDEX (N4)
*
END-DEFINE
*
RESET XMLVALP-DEFAULT
*
EXAMINE FULL XML-SCHEMA FOR '/' GIVING POSITION IN #INDEX
IF #INDEX LE 0
  COMPRESS #DEFAULT-SCHEMA-PATH XML-SCHEMA INTO XML-SCHEMA LEAVING NO
END-IF
*
COMPRESS '/tmp/XML-Validation-' *DATN '-' *TIMN '.txt' INTO #TEMPFILE LEAVING NO
COMPRESS '/usr/bin/java -cp' #DEFAULT-SCHEMA-PATH 'XMLValidator' XML-FILE XML-SCHEMA '>' #TEMPFILE INTO OS-COMMAND
*
CALLNAT 'USR1052N' USR1052L
XMLVALP.XML-RESULT := RESPONSE
*
IF XMLVALP.XML-RESULT NE VALID-XML
  DEFINE WORK FILE 1 #TEMPFILE TYPE 'ASCII'
  READ WORK 1 #WORK
    COMPRESS XML-ERROR #WORK INTO XMLVALP.XML-ERROR
  END-WORK
  CLOSE WORK 1
END-IF
*
COMPRESS 'rm' #TEMPFILE INTO OS-COMMAND
CALLNAT 'USR1052N' USR1052L
*
END

The Java validator is pretty straightforward:
package xml; import java.io.File; import java.io.IOException; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import org.w3c.dom.Document; import org.xml.sax.SAXParseException; public class XMLValidator { private final static int INVALID_PARAMETERS = 1; private final static int INVALID_XML = 2; private final static int INVALID_FILE = 3; private final static int ANY_ERROR = 4; public static void main(String[] args) { if (args.length != 2) { System.out.println("Usage: XMLValidator PathToXMLFile PathToSchemaFile"); System.exit(INVALID_PARAMETERS); } String xmlFile = args[0]; String xsdFile = args[1]; try { validateXml(xmlFile, xsdFile); } catch (Exception e) { System.out.println("Error: " + e.getMessage()); System.exit(ANY_ERROR); } } private static void validateXml(String xmlFile, String xsdFile) throws Exception { // create a factory that understands namespaces and validates the XML input DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); try { // read the XML file DocumentBuilder builder = factory.newDocumentBuilder(); Document mDoc = builder.parse(new File(xmlFile)); // create a SchemaFactory capable of understanding schemas SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); // load the schema Schema schema = schemaFactory.newSchema(new File(xsdFile)); // validate the XML file Validator validator = schema.newValidator(); validator.validate(new DOMSource(mDoc)); } catch (SAXParseException spe) { // error generated by the parser System.out.println("Parser error: URI " + spe.getSystemId() + ", Line " + spe.getLineNumber() + ", Message: " + spe.getMessage()); System.exit(INVALID_XML); } catch (IOException ioe) { System.out.println("Error reading file '" + xmlFile + "'."); System.exit(INVALID_FILE); } } }

Download

Über Stefan

Polyglot Clean Code Developer

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax