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