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:

  1. package xml;
  2.  
  3. import java.io.File;
  4. import java.io.IOException;
  5.  
  6. import javax.xml.XMLConstants;
  7. import javax.xml.parsers.DocumentBuilder;
  8. import javax.xml.parsers.DocumentBuilderFactory;
  9. import javax.xml.transform.dom.DOMSource;
  10. import javax.xml.validation.Schema;
  11. import javax.xml.validation.SchemaFactory;
  12. import javax.xml.validation.Validator;
  13.  
  14. import org.w3c.dom.Document;
  15. import org.xml.sax.SAXParseException;
  16.  
  17. public class XMLValidator
  18. {
  19.     private final static int INVALID_PARAMETERS = 1;
  20.     private final static int INVALID_XML = 2;
  21.     private final static int INVALID_FILE = 3;
  22.     private final static int ANY_ERROR = 4;
  23.  
  24.     public static void main(String[] args)
  25.     {
  26.         if (args.length != 2)
  27.         {
  28.             System.out.println("Usage: XMLValidator PathToXMLFile PathToSchemaFile");
  29.             System.exit(INVALID_PARAMETERS);
  30.         }
  31.  
  32.         String xmlFile = args[0];
  33.         String xsdFile = args[1];
  34.  
  35.         try
  36.         {
  37.             validateXml(xmlFile, xsdFile);
  38.         }
  39.         catch (Exception e)
  40.         {
  41.             System.out.println("Error: " + e.getMessage());
  42.             System.exit(ANY_ERROR);
  43.         }
  44.     }
  45.  
  46.     private static void validateXml(String xmlFile, String xsdFile) throws Exception
  47.     {
  48.         // create a factory that understands namespaces and validates the XML input
  49.         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  50.         factory.setNamespaceAware(true);
  51.  
  52.         try
  53.         {
  54.             // read the XML file
  55.             DocumentBuilder builder = factory.newDocumentBuilder();
  56.             Document mDoc = builder.parse(new File(xmlFile));
  57.  
  58.             // create a SchemaFactory capable of understanding schemas
  59.             SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
  60.  
  61.             // load the schema
  62.             Schema schema = schemaFactory.newSchema(new File(xsdFile));
  63.  
  64.             // validate the XML file
  65.             Validator validator = schema.newValidator();
  66.             validator.validate(new DOMSource(mDoc));
  67.         }
  68.         catch (SAXParseException spe)
  69.         {
  70.             // error generated by the parser
  71.             System.out.println("Parser error: URI " + spe.getSystemId() + ", Line " + spe.getLineNumber() + ", Message: " + spe.getMessage());
  72.             System.exit(INVALID_XML);
  73.         }
  74.         catch (IOException ioe)
  75.         {
  76.             System.out.println("Error reading file ‚" + xmlFile + "‘.");
  77.             System.exit(INVALID_FILE);
  78.         }
  79.     }
  80. }

Download

Über uns 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