diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ab697c..a68d2a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ All notable changes to the Schematron Rules and this project will be documented The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Upcoming version +## 1.1.2 +### Fixed +- NPE in Result.getReportDocument for malformed xml input #Added - Support java.xml.transform.Source/java.xml.transform.StreamSource as Input diff --git a/pom.xml b/pom.xml index 70c7b3d..5667370 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,6 @@ http://www.xoev.de - renzo.kottmann Renzo Kottmann KoSIT @@ -37,12 +36,6 @@ developer - - fabian.buettner - Fabian Büttner - KoSIT - http://www.xoev.de - UTF-8 diff --git a/src/main/java/de/kosit/validationtool/impl/DefaultCheck.java b/src/main/java/de/kosit/validationtool/impl/DefaultCheck.java index 257a765..02e2922 100644 --- a/src/main/java/de/kosit/validationtool/impl/DefaultCheck.java +++ b/src/main/java/de/kosit/validationtool/impl/DefaultCheck.java @@ -43,7 +43,6 @@ import de.kosit.validationtool.impl.tasks.SchematronValidationAction; import de.kosit.validationtool.impl.tasks.ValidateReportInputAction; import de.kosit.validationtool.model.reportInput.CreateReportInput; import de.kosit.validationtool.model.reportInput.EngineType; -import de.kosit.validationtool.model.reportInput.ProcessingError; import de.kosit.validationtool.model.reportInput.XMLSyntaxError; import net.sf.saxon.s9api.Processor; @@ -116,12 +115,6 @@ public class DefaultCheck implements Check { action.check(t); } log.debug("Step {} finished in {}ms", action.getClass().getSimpleName(), System.currentTimeMillis() - start); - if (t.isStopped()) { - final ProcessingError processingError = t.getReportInput().getProcessingError(); - log.error("Error processing input {}: {}", t.getInput().getName(), - processingError != null ? String.join("\n", processingError.getError()) : ""); - break; - } } t.setFinished(true); log.info("Finished check of {} in {}ms\n", t.getInput().getName(), System.currentTimeMillis() - started); diff --git a/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java b/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java index be32ca9..71c723f 100644 --- a/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java +++ b/src/main/java/de/kosit/validationtool/impl/model/BaseScenario.java @@ -94,7 +94,7 @@ public abstract class BaseScenario { * @return das passende Schema */ public Schema getSchema() { - if (this.schema == null) { + if (this.schema == null && getValidateWithXmlSchema() != null) { final List schemaResources = getValidateWithXmlSchema().getResource().stream().map(ResourceType::getLocation) .collect(Collectors.toList()); this.schema = this.repository.createSchema(schemaResources); diff --git a/src/main/java/de/kosit/validationtool/impl/tasks/CreateReportAction.java b/src/main/java/de/kosit/validationtool/impl/tasks/CreateReportAction.java index 87d0256..b8bab3d 100644 --- a/src/main/java/de/kosit/validationtool/impl/tasks/CreateReportAction.java +++ b/src/main/java/de/kosit/validationtool/impl/tasks/CreateReportAction.java @@ -22,6 +22,7 @@ package de.kosit.validationtool.impl.tasks; import javax.xml.transform.dom.DOMSource; import org.w3c.dom.Document; +import org.xml.sax.SAXException; import lombok.RequiredArgsConstructor; @@ -31,9 +32,9 @@ import de.kosit.validationtool.impl.ConversionService; import de.kosit.validationtool.impl.ObjectFactory; import de.kosit.validationtool.impl.RelativeUriResolver; import de.kosit.validationtool.impl.ScenarioRepository; -import de.kosit.validationtool.impl.model.Result; import de.kosit.validationtool.model.scenarios.ScenarioType; +import net.sf.saxon.s9api.BuildingContentHandler; import net.sf.saxon.s9api.DocumentBuilder; import net.sf.saxon.s9api.Processor; import net.sf.saxon.s9api.QName; @@ -70,7 +71,7 @@ public class CreateReportAction implements CheckAction { try { final XdmNode parsedDocument = results.getParserResult().isValid() ? results.getParserResult().getObject() - : ObjectFactory.createProcessor().newDocumentBuilder().newBuildingContentHandler().getDocumentNode(); + : createEmpty(); final Document reportInput = this.conversionService.writeDocument(results.getReportInput()); final XdmNode root = documentBuilder.build(new DOMSource(reportInput)); @@ -81,21 +82,27 @@ public class CreateReportAction implements CheckAction { transformer.setMessageListener(e); transformer.setURIResolver(resolver); transformer.getUnderlyingController().setUnparsedTextURIResolver(resolver); - transformer.setParameter(new QName("input-document"), parsedDocument); + if (parsedDocument != null) { + transformer.setParameter(new QName("input-document"), parsedDocument); + } final XdmDestination destination = new XdmDestination(); transformer.setDestination(destination); transformer.transform(); results.setReport(destination.getXdmNode()); - } catch (final SaxonApiException e) { + } catch (final SaxonApiException | SAXException e) { throw new IllegalStateException("Can not create final report", e); } } - private XsltExecutable getTransformation(final Bag results) { - final Result scenario = results.getScenarioSelectionResult(); - final ScenarioType reportScenario = scenario.isValid() ? scenario.getObject() : this.scenarioRepository.getFallbackScenario(); - return loadFromScenario(reportScenario); + private static XdmNode createEmpty() throws SaxonApiException, SAXException { + final BuildingContentHandler contentHandler = ObjectFactory.createProcessor().newDocumentBuilder().newBuildingContentHandler(); + contentHandler.startDocument(); + return contentHandler.getDocumentNode(); + } + + private static XsltExecutable getTransformation(final Bag results) { + return loadFromScenario(results.getScenarioSelectionResult().getObject()); } } diff --git a/src/main/java/de/kosit/validationtool/impl/tasks/ScenarioSelectionAction.java b/src/main/java/de/kosit/validationtool/impl/tasks/ScenarioSelectionAction.java index 10a7bbd..c66eead 100644 --- a/src/main/java/de/kosit/validationtool/impl/tasks/ScenarioSelectionAction.java +++ b/src/main/java/de/kosit/validationtool/impl/tasks/ScenarioSelectionAction.java @@ -26,8 +26,11 @@ import de.kosit.validationtool.impl.model.Result; import de.kosit.validationtool.model.reportInput.CreateReportInput; import de.kosit.validationtool.model.scenarios.ScenarioType; +import net.sf.saxon.s9api.XdmNode; + /** - * Identifiziert das der Eingabe entsprechende Szenario, sofern eines konfiguriert ist. + * Identifiziert das der Eingabe entsprechende Szenario, sofern eines konfiguriert ist. Setzt das Fallback-Szenario, + * wenn keines identifiziert werden konnte. * * @author Andreas Penski */ @@ -39,18 +42,23 @@ public class ScenarioSelectionAction implements CheckAction { @Override public void check(final Bag results) { final CreateReportInput report = results.getReportInput(); - final Result scenarioTypeResult = this.repository.selectScenario(results.getParserResult().getObject()); - results.setScenarioSelectionResult(scenarioTypeResult); - if (scenarioTypeResult.isValid()) { - final ScenarioType scenario = scenarioTypeResult.getObject(); - report.setScenario(scenario); + final Result scenarioTypeResult; + + if (results.getParserResult().isValid()) { + scenarioTypeResult = determineScenario(results.getParserResult().getObject()); } else { - results.stopProcessing(scenarioTypeResult.getErrors()); + scenarioTypeResult = new Result<>(repository.getFallbackScenario()); } + results.setScenarioSelectionResult(scenarioTypeResult); + report.setScenario(scenarioTypeResult.getObject()); } - @Override - public boolean isSkipped(final Bag results) { - return results.getParserResult().isInvalid(); + private Result determineScenario(final XdmNode document) { + final Result result = this.repository.selectScenario(document); + if (result.isInvalid()) { + return new Result<>(repository.getFallbackScenario()); + } + return result; } + } diff --git a/src/main/java/de/kosit/validationtool/impl/tasks/SchemaValidationAction.java b/src/main/java/de/kosit/validationtool/impl/tasks/SchemaValidationAction.java index fc4843e..66b0c7d 100644 --- a/src/main/java/de/kosit/validationtool/impl/tasks/SchemaValidationAction.java +++ b/src/main/java/de/kosit/validationtool/impl/tasks/SchemaValidationAction.java @@ -58,7 +58,7 @@ import net.sf.saxon.s9api.XdmNode; * functionality and therefore needs a {@link Source} to do the actual validation. Since we base the validator on Saxon * HE functionality, we have no support for schema in Saxon (e.g. the in memory version of the document is not * schema-aware) and need to re-read the actual source. - * + * * Since the actual {@link Input} implementation may not be read twice, we must serialize the previously read document. * This implementation tries to do the validation in an efficient manner. If possible the source is read a second time * to validate. If not, the source is serialized to the heap upon re-read/validaiton up to a configurable file size. The @@ -187,11 +187,11 @@ public class SchemaValidationAction implements CheckAction { @Override public boolean isSkipped(final Bag results) { - return hasNoScenario(results); + return hasNoSchema(results); } - private static boolean hasNoScenario(final Bag results) { - return results.getScenarioSelectionResult() == null || results.getScenarioSelectionResult().isInvalid(); + private static boolean hasNoSchema(final Bag results) { + return results.getScenarioSelectionResult() == null || results.getScenarioSelectionResult().getObject().getSchema() == null; } private interface SourceProvider extends AutoCloseable { diff --git a/src/main/java/de/kosit/validationtool/impl/tasks/SchematronValidationAction.java b/src/main/java/de/kosit/validationtool/impl/tasks/SchematronValidationAction.java index 2fe271a..0063da7 100644 --- a/src/main/java/de/kosit/validationtool/impl/tasks/SchematronValidationAction.java +++ b/src/main/java/de/kosit/validationtool/impl/tasks/SchematronValidationAction.java @@ -95,6 +95,10 @@ public class SchematronValidationAction implements CheckAction { @Override public boolean isSkipped(final Bag results) { - return results.getSchemaValidationResult() == null || results.getSchemaValidationResult().isInvalid(); + return hasNoSchematrons(results.getScenarioSelectionResult().getObject()); + } + + private static boolean hasNoSchematrons(final ScenarioType object) { + return object.getValidateWithSchematron() == null || object.getValidateWithSchematron().size() == 0; } } diff --git a/src/test/java/de/kosit/validationtool/impl/DefaultCheckTest.java b/src/test/java/de/kosit/validationtool/impl/DefaultCheckTest.java index 5fa5487..c384039 100644 --- a/src/test/java/de/kosit/validationtool/impl/DefaultCheckTest.java +++ b/src/test/java/de/kosit/validationtool/impl/DefaultCheckTest.java @@ -127,6 +127,9 @@ public class DefaultCheckTest { assertThat(result.isWellformed()).isFalse(); assertThat(result.isSchemaValid()).isFalse(); assertThat(result.isProcessingSuccessful()).isFalse(); + assertThat(result.getAcceptRecommendation()).isEqualTo(AcceptRecommendation.REJECT); + assertThat(result.getReport()).isNotNull(); + assertThat(result.getReportDocument()).isNotNull(); } } diff --git a/src/test/java/de/kosit/validationtool/impl/Helper.java b/src/test/java/de/kosit/validationtool/impl/Helper.java index 14882a7..f0e913d 100644 --- a/src/test/java/de/kosit/validationtool/impl/Helper.java +++ b/src/test/java/de/kosit/validationtool/impl/Helper.java @@ -22,13 +22,21 @@ package de.kosit.validationtool.impl; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Paths; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import org.w3c.dom.Document; + +import net.sf.saxon.dom.NodeOverNodeInfo; import net.sf.saxon.s9api.SaxonApiException; import net.sf.saxon.s9api.XdmNode; @@ -133,4 +141,18 @@ public class Helper { return new ContentRepository(ObjectFactory.createProcessor(), new File("src/test/resources/examples/repository").toURI()); } + public static String serialize(final Document doc) { + try ( final StringWriter writer = new StringWriter() ) { + final Transformer transformer = ObjectFactory.createTransformer(true); + transformer.transform(new DOMSource(doc), new StreamResult(writer)); + return writer.toString(); + } catch (final IOException | TransformerException e) { + throw new IllegalStateException("Can not serialize document", e); + } + } + + public static String serialize(final XdmNode node) { + return serialize((Document) NodeOverNodeInfo.wrap(node.getUnderlyingNode())); + } + }