/**
* Copyright (c) Codice Foundation
* <p/>
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
* <p/>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package ddf.services.schematron;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Schematron Validation Report Language (SVRL) formatted report of output from Schematron
* validation.
*
* @author rodgersh
*
*/
public class SvrlReport implements SchematronReport {
/** SVRL report tag for assertion that failed during Schematron validation */
private static final String ASSERT_FAIL_TAG = "svrl:failed-assert";
/** SVRL report tag for report that failed during Schematron validation */
private static final String REPORT_FAIL_TAG = "svrl:failed-report";
/**
* SVRL report tag for flag attribute in a svrl:failed-assert element that indicates if the
* failure is an error or warning
*/
private static final String FLAG_ATTR = "flag";
/**
* Value for svrl:failed-assert tag's flag attribute for warnings.
*
* Example: <svrl:failed-assert test="if(invalid) then 1 else not($hasInvalids)" flag="warning">
* ... </svrl:failed-assert>
*/
private static final String WARNING_FLAG_ATTR_TEXT = "warning";
/**
* Value for svrl:failed-assert tag's flag attribute for errors
*
* Example: <svrl:failed-assert test="if(invalid) then 1 else not($hasInvalids)" flag="error">
* ... </svrl:failed-assert>
*/
private static final String ERROR_FLAG_ATTR_TEXT = "error";
private static final Logger LOGGER = LoggerFactory.getLogger(SvrlReport.class);
/** Schematron report in DOM format */
private DOMResult report;
/** The root element of the report's DOM tree. */
private Element root = null;
/**
* Private default constructor to prevent instantiating SvrlReport without required DOMResult
* argument.
*/
private SvrlReport() {
}
/**
* @param result
* DOM-formatted results from Schematron validation
*/
public SvrlReport(DOMResult result) {
this.report = result;
this.root = (Element) report.getNode().getFirstChild();
}
/**
* Returns true if Schematron report is valid, false otherwise. The input document is considered
* to be valid if it has no failed assertions for errors and no failed reports for errors. If
* the suppressWarnings argument is true, then Schematron warnings are also included in the
* document's validity assessment.
*
* @param suppressWarnings
* do not include Schematron warnings in determining validity
*
* @return true if no assert or report error messages found in SVRL report, false otherwise
*/
@Override
public boolean isValid(boolean suppressWarnings) {
List<Node> errorAssertions = getAllAssertMessages(ERROR_FLAG_ATTR_TEXT);
List<Node> errorReports = getAllReportMessages(ERROR_FLAG_ATTR_TEXT);
if (errorAssertions.size() != 0 || errorReports.size() != 0) {
return false;
}
if (!suppressWarnings) {
List<Node> warningAssertions = getAllAssertMessages(WARNING_FLAG_ATTR_TEXT);
List<Node> warningReports = getAllReportMessages(WARNING_FLAG_ATTR_TEXT);
if (warningAssertions.size() != 0 || warningReports.size() != 0) {
return false;
}
}
return true;
}
/**
* Retrieve all assertion messages, warnings and errors, from the SVRL report.
*
* @return list of XML Nodes for all assert nodes
*/
@Override
public NodeList getAllAssertMessages() {
return root.getElementsByTagName(ASSERT_FAIL_TAG);
}
/**
* Retrieve only the specified type of assertion messages (warnings or errors) from the SVRL
* report.
*
* @parameter type the type of assert message to search for in SVRL report, "warning" or "error"
* @return list of XML Nodes for all assert nodes of specified type
*/
public List<Node> getAllAssertMessages(String type) {
List<Node> assertions = new ArrayList<Node>();
NodeList assertFailures = getAllAssertMessages();
for (int i = 0; i < assertFailures.getLength(); i++) {
Node assertion = assertFailures.item(i);
NamedNodeMap attributes = assertion.getAttributes();
Node flagNode = attributes.getNamedItem(FLAG_ATTR);
if (flagNode != null && flagNode.getNodeValue().equals(type)) {
assertions.add(assertion);
}
}
return assertions;
}
/**
* Retrieve all report messages, warnings and errors, from the SVRL report.
*
* @return list of XML Nodes for all report nodes
*/
@Override
public NodeList getAllReportMessages() {
return root.getElementsByTagName(REPORT_FAIL_TAG);
}
/**
* Retrieve only the specified type of report messages (warnings or errors) from the SVRL
* report.
*
* @parameter type the type of report message to search for in SVRL report, "warning" or "error"
* @return list of XML Nodes for all report nodes
*/
public List<Node> getAllReportMessages(String type) {
List<Node> reports = new ArrayList<Node>();
NodeList reportFailures = getAllReportMessages();
for (int i = 0; i < reportFailures.getLength(); i++) {
Node report = reportFailures.item(i);
NamedNodeMap attributes = report.getAttributes();
Node flagNode = attributes.getNamedItem(FLAG_ATTR);
if (flagNode != null && flagNode.getNodeValue().equals(type)) {
reports.add(report);
}
}
return reports;
}
/**
* Get a list of all of the assertion and report error messages from the SVRL report.
*
* @return list of error strings
*/
@Override
public List<String> getErrors() {
List<String> errors = new ArrayList<String>();
List<Node> errorAssertions = getAllAssertMessages(ERROR_FLAG_ATTR_TEXT);
for (Node error : errorAssertions) {
errors.add(error.getFirstChild().getTextContent());
}
List<Node> errorReports = getAllReportMessages(ERROR_FLAG_ATTR_TEXT);
for (Node error : errorReports) {
errors.add(error.getFirstChild().getTextContent());
}
return errors;
}
/**
* Get a list of all of the assertion and report warning messages from the SVRL report.
*
* @return list of warning strings
*/
@Override
public List<String> getWarnings() {
List<String> warnings = new ArrayList<String>();
List<Node> warningAssertions = getAllAssertMessages(WARNING_FLAG_ATTR_TEXT);
for (Node warning : warningAssertions) {
LOGGER.debug("warning(from assertions) = " + warning.getFirstChild().getTextContent());
warnings.add(warning.getFirstChild().getTextContent());
}
List<Node> warningReports = getAllReportMessages(WARNING_FLAG_ATTR_TEXT);
for (Node warning : warningReports) {
LOGGER.debug("warning(from reports) = " + warning.getFirstChild().getTextContent());
warnings.add(warning.getFirstChild().getTextContent());
}
return warnings;
}
/**
* Retrieve the entire SVRL report as an XML-formatted string.
*
* @return XML-formatted string representation of SVRL report
*/
@Override
public String getReportAsText() throws TransformerException {
Writer sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
TransformerFactory tfactory = TransformerFactory.newInstance();
Transformer transformer = tfactory.newTransformer();
Properties props = new Properties();
props.put("method", "xml");
props.put("indent", "yes");
transformer.setOutputProperties(props);
transformer.transform(new DOMSource(root), new StreamResult(out));
out.close();
return sw.toString();
}
};