/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.esri.gpt.catalog.schema;
import com.esri.gpt.framework.util.LogUtil;
import com.esri.gpt.framework.util.Val;
import com.esri.gpt.framework.xml.DomUtil;
import com.esri.gpt.framework.xml.XsltTemplate;
import com.esri.gpt.framework.xml.XsltTemplates;
import java.io.IOException;
import java.util.logging.Level;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Validates a document against a Schematron XSLT.
* <p/>
* The XSLT must produce an SVRL document (Schematron Validation Report Language).
*/
public class SchematronValidator {
// class variables =============================================================
private static XsltTemplates XSLTTEMPLATES = new XsltTemplates();
// instance variables ==========================================================
private ValidationErrors _validationErrors;
// constructors ================================================================
/** Default constructor. */
public SchematronValidator() {}
// properties ==================================================================
/**
* Gets the validation errors.
* @return the validation errors
*/
protected ValidationErrors getValidationErrors() {
return _validationErrors;
}
/**
* Sets the validation errors.
* @param errors validation errors
*/
protected void setValidationErrors(ValidationErrors errors) {
_validationErrors = errors;
if (_validationErrors == null) _validationErrors = new ValidationErrors();
}
// methods =====================================================================
/**
* Gets a compiled XSLT template.
* @param xsltPath the path to an XSLT
* @return the compiled template
* @throws IOException if an IO exception occurs
* @throws TransformerException if a transformation exception occurs
*/
private synchronized XsltTemplate getCompiledTemplate(String xsltPath)
throws TransformerException {
String sKey = xsltPath;
XsltTemplate template = XSLTTEMPLATES.get(sKey);
if (template == null) {
template = XsltTemplate.makeTemplate(xsltPath);
XSLTTEMPLATES.put(sKey,template);
}
return template;
}
/**
* Validates an XML string against a Schematron XSLT associated with a schema.
* @param schema the schema being validated
* @param xml the XML string to be validated
* @throws ValidationException if validation errors were located
*/
public void validate(Schema schema, String xml) throws ValidationException {
setValidationErrors(new ValidationErrors());
if (schema.getSchematronXslt().length() > 0) {
String schematronXslt = null;
try {
String[] tokens = schema.getSchematronXslt().split(",");
for (String token: tokens) {
schematronXslt = Val.chkStr(token);
if (schematronXslt.length() == 0) continue;
// run the validation xsl
XsltTemplate template = this.getCompiledTemplate(schematronXslt);
String result = template.transform(xml);
// load the result SVRL document
Document dom = DomUtil.makeDomFromString(result,true);
Namespaces namespaces = new Namespaces();
namespaces.add("svrl","http://purl.oclc.org/dsdl/svrl");
NamespaceContextImpl nsc = new NamespaceContextImpl(namespaces);
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(nsc);
// check for failed assertions
NodeList nl = (NodeList)xpath.evaluate("//svrl:failed-assert",dom,XPathConstants.NODESET);
for (int i=0;i<nl.getLength();i++) {
Node nd = nl.item(i);
String sLocation = Val.chkStr(xpath.evaluate("@location",nd));
String sText = Val.chkStr(xpath.evaluate("svrl:text",nd));
if (sText.length() == 0) {
sText = "Untitled Schematron assertion failure.";
}
ValidationError error = new ValidationError();
//error.location = sLocation;
error.setMessage(sText);
error.setReasonCode(ValidationError.REASONCODE_SCHEMATRON_VIOLATION);
getValidationErrors().add(error);
}
}
} catch (Exception e) {
String sMsg = "Error executing schematron validation, schema="+
schema.getKey()+" schematronXslt="+schematronXslt;
LogUtil.getLogger().log(Level.SEVERE,sMsg,e);
ValidationError error = new ValidationError();
error.setMessage(sMsg);
error.setReasonCode(ValidationError.REASONCODE_SCHEMATRON_EXCEPTION);
getValidationErrors().add(error);
throw new ValidationException(schema.getKey(),sMsg,getValidationErrors());
}
}
if (getValidationErrors().size() > 0) {
throw new ValidationException(schema.getKey(),"Schematron violation.",getValidationErrors());
}
}
}