15

I create simple XML file in my SAS program:

data _null_;
   file "C:\persons.xml";
   put "<?xml version=""1.0"" encoding=""UTF-8""?>";
   put "<Person>";
   put "<Name>John</Name>";
   put "<Age>32</Age>";
   put "</Person>";
run;

And I have XML Schema (xsd file). I want to validate my file with schema and put error if the file does not match the shema. Is it possible?

Thanks in advance!

PierreVanStulov
  • 425
  • 2
  • 11
  • You want to do this using SAS, or using another tool? – Joe Nov 03 '15 at 17:28
  • Joe, I want to do this in SAS program. – PierreVanStulov Nov 03 '15 at 19:49
  • SAS can run `R` and the `R` function `xmlSchemaValidate` can validate XML towards a schema, but I am afraid it requires installing extra R modules within your SAS instalation. – Dirk Horsten Sep 07 '17 at 07:59
  • Have you considered using the XML libname approach instead to create your XML files? Combined with an XML map (search for SAS XML Mapper) it should be flexible enough to do what you need. Also very little coding is involved. – Robert Penridge Oct 31 '17 at 15:59
  • Can you update the question with the xsd or a link to it ? – Richard Apr 26 '18 at 18:34

1 Answers1

2

As @robert-penridge mentioned, there exist something called XMLv2 engine. However, it is not possible to validate it directly in SAS, as XMLv2 engine does not validate xml against xsd, and it assumes it is a proper XML...

There is a way to do it with JAVA and SAS (works for SAS 9.3+, not sure about earlier versions). So, you need to place this java file somewhere where you can reach it through SAS.

Java Code (has to be named XMLValidator.java):

import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.IOException;

class XMLValidator{

    File schemaFile;
    File xmlFile;
    XMLValidator(String pathXSD, String pathXML){
        this.schemaFile = new File(pathXSD);
    this.xmlFile=new File(pathXML);
    }

public int validate(){
    Source xmlSource = new StreamSource(xmlFile);
    SchemaFactory schemaFactory = SchemaFactory
        .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    try {
        Schema schema = schemaFactory.newSchema(schemaFile);
        Validator validator = schema.newValidator();
        validator.validate(xmlSource);
        return 0; // schema is valid
        } catch (SAXException e) {
        System.out.println(xmlSource.getSystemId() + " is NOT valid reason:" + e);
        return 1; // schema is not valid
    } catch (IOException e) {
        return 2;
    }
        }
    public static void main(String [ ] args){
        XMLValidator validator=new XMLValidator(args[1],args[2]);
        System.out.println(validator.validate());
    }
}

When compiled (with javac XMLValidator.java), remember the path where you saved it.

Now you can use the following SAS Code to validate XML:

%macro init_classpath_update;
  DATA _null_;
      LENGTH  path_separator $ 2
              orig_classpath $ 32767;

      DECLARE JavaObj f("java.io.File", "");
      f.getStaticStringField("pathSeparator", path_separator);

      orig_classpath = STRIP(SYSGET("CLASSPATH"));

      IF _ERROR_ = 1 OR LENGTH(orig_classpath) = 0 THEN DO;
      PUT "NOTE: Ignore any messages from the next statement(s)";
          orig_classpath = "";
    END;

      CALL SYMPUTX('CP_orig_classpath', STRIP(orig_classpath), 'GLOBAL');
      CALL SYMPUTX('CP_path_separator', COMPRESS(path_separator), 'GLOBAL');
  RUN;
%mend;

%macro add_to_classpath(cp_addition);
  DATA _null_;
      LENGTH  current_classpath $ 32767
              new_classpath $ 32767;

      current_classpath = STRIP(SYSGET("CLASSPATH"));

      IF _ERROR_ = 1 OR LENGTH(current_classpath) = 0 THEN DO;
      PUT "NOTE: Ignore any messages from the nearby statement(s)";
          new_classpath = "&cp_addition";
    END;
      ELSE DO;
          new_classpath = COMPRESS(current_classpath) || "&CP_path_separator" || "&cp_addition";
    END;

      CALL SYMPUTX('CP_new_classpath', STRIP(new_classpath), 'GLOBAL');
  RUN;

  %PUT NOTE: Setting Java classpath to &CP_new_classpath;
  OPTIONS SET=CLASSPATH "&CP_new_classpath";
%mend;

%macro reset_classpath;
  %PUT NOTE: Setting Java classpath back to its original state: &CP_orig_classpath;
  OPTIONS SET=CLASSPATH "&CP_orig_classpath";
%mend;

proc javainfo;
run;

%init_classpath_update;
%add_to_classpath(<path_where_you_saved_your_compiled_XMLValidator_file>/.);

data _null_;
     length rtn_val 8;
   declare javaobj xsdPath("java/lang/String","<path_to_your_xsd_file_as_absolute_path>");
   declare javaobj xmlPath("java/lang/String","<path_to_your_xml_file_as_absolute_path>");
   declare javaobj xmlValidator("XMLValidator",xsdPath,xmlPath);
   rc = xmlValidator.callIntMethod("validate",rtn_val);
   xsdPath.delete();
   xmlPath.delete();
   xmlValidator.delete();
  putlog rc= rtn_val=;
run;

This code will return 0 if the validation is successful, and 1 or 2 if the validation has failed.

kwx
  • 28
  • 4
Sale
  • 349
  • 1
  • 3
  • 15