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!
You can validate your XML documents against XML schemas only; validation against DTDs is not supported. However, although you cannot validate against DTDs, you can insert documents that contain a DOCTYPE or that refer to DTDs.
XML documents can be validated against an XML schema definition language (XSD) schema in an XmlSchemaSet. XML documents are validated by the Create method of the XmlReader class. To validate an XML document, construct an XmlReaderSettings object that contains an XML schema definition language (XSD) schema with which to validate the XML document.
Read and write XML Schema definition language (XSD) schemas from files or other sources in .NET, using the Schema Object Model (SOM) API. You can use extension methods from the System.Xml.Schema namespace to validate an XML tree against an XML Schema Definition Language (XSD) file.
Validating XML Documents. XML documents are validated by the Create method of the XmlReader class. To validate an XML document, construct an XmlReaderSettings object that contains an XML schema definition language (XSD) schema with which to validate the XML document.
Finally, call a validate() method on a validator object by inputting XML file. We should also create ErrorHandlerby an overriding warning(), error() and fatal() methods and pass this to setErrorHandler() on validator, which captures xsd messages. When you run this example, it returns all XSD error, fatal and warning messages in a list. Output:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With