diff --git a/src/main/java/eu/europa/ted/eforms/sdk/analysis/domain/schematron/SchematronAssert.java b/src/main/java/eu/europa/ted/eforms/sdk/analysis/domain/schematron/SchematronAssert.java index f2b541d..1c8edd5 100644 --- a/src/main/java/eu/europa/ted/eforms/sdk/analysis/domain/schematron/SchematronAssert.java +++ b/src/main/java/eu/europa/ted/eforms/sdk/analysis/domain/schematron/SchematronAssert.java @@ -2,16 +2,22 @@ public class SchematronAssert { private final String id; + private final String patternId; private String diagnostics; - public SchematronAssert(String id) { + public SchematronAssert(String id, String patternId) { this.id = id; + this.patternId = patternId; } public String getId() { return id; } + public String getPatternId() { + return patternId; + } + public String getDiagnostics() { return diagnostics; } diff --git a/src/main/java/eu/europa/ted/eforms/sdk/analysis/fact/SchematronFileFact.java b/src/main/java/eu/europa/ted/eforms/sdk/analysis/fact/SchematronFileFact.java index 97140a7..4758d2a 100644 --- a/src/main/java/eu/europa/ted/eforms/sdk/analysis/fact/SchematronFileFact.java +++ b/src/main/java/eu/europa/ted/eforms/sdk/analysis/fact/SchematronFileFact.java @@ -1,7 +1,9 @@ package eu.europa.ted.eforms.sdk.analysis.fact; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -40,9 +42,32 @@ public List getPatterns() { return schematronFile.getPatterns(); } + /** + * Return the list of assert identifiers that appear more than once in the same phase. + * + * @return list of duplicate assert ids + */ public List getDuplicateAssertIds() { - Set set = new HashSet(); - return getAsserts().stream().map(SchematronAssert::getId).filter(id -> !set.add(id)) + // Mpa from the pattern id to the id of the phase it is part of + Map patternToPhase = new HashMap<>(); + getPhases().forEach(phase -> { + phase.getActivePatterns() + .forEach(patternId -> { + patternToPhase.put(patternId, phase.getId()); + }); + }); + + // Map from phase id to the set of assert ids it contains. + Map> phaseToAssertIds = new HashMap>(); + return getAsserts().stream() + .filter(assrt -> { + String phaseId = patternToPhase.get(assrt.getPatternId()); + Set asserts = + phaseToAssertIds.computeIfAbsent(phaseId, k -> new HashSet()); + // Keep SchematronAssert if its is already present in the same phase + return !asserts.add(assrt.getId()); + }) + .map(SchematronAssert::getId) .collect(Collectors.toList()); } diff --git a/src/main/java/eu/europa/ted/eforms/sdk/analysis/util/SchematronParser.java b/src/main/java/eu/europa/ted/eforms/sdk/analysis/util/SchematronParser.java index 1a2cbf9..ccc7dbd 100644 --- a/src/main/java/eu/europa/ted/eforms/sdk/analysis/util/SchematronParser.java +++ b/src/main/java/eu/europa/ted/eforms/sdk/analysis/util/SchematronParser.java @@ -96,30 +96,44 @@ public static SchematronFile loadSchematronFile(Path schematronFilePath) { } // Parse all patterns - List patterns = allChildren.stream() + List patterns = new ArrayList<>(); + List asserts = new ArrayList<>(); + allChildren.stream() .filter(node -> node.isElement() && "pattern".equals(node.getNodeName())) - .map(n -> ((IMicroElement)n).getAttributeValue("id")) - .map(s -> new SchematronPattern(s)) - .collect(Collectors.toList()); + .forEach(patternNode -> { + String patternId = ((IMicroElement)patternNode).getAttributeValue("id"); + SchematronPattern pattern = new SchematronPattern(patternId); + patterns.add(pattern); + asserts.addAll(parseAsserts(patternId, patternNode)); + }); schematronFile.setPatterns(patterns); + schematronFile.setAsserts(asserts); - // Parse all asserts + return schematronFile; + } + + private static List parseAsserts(String patternId, IMicroNode patternNode) { List asserts = new ArrayList<>(); - allChildren.stream() + + List children = patternNode.getAllChildrenRecursive(); + if (children == null) { + logger.error("Schematron file has unexpected structure in pattern", patternId); + // return an empty list, so that the prasing can continue + return asserts; + } + + children.stream() .filter(node -> node.isElement() && "assert".equals(node.getNodeName())) .forEach(n -> { IMicroElement element = (IMicroElement)n; - String id = element.getAttributeValue("id"); - SchematronAssert schematronAssert = new SchematronAssert(id); + String assertId = element.getAttributeValue("id"); + SchematronAssert schematronAssert = new SchematronAssert(assertId, patternId); String diag = element.getAttributeValue("diagnostics"); schematronAssert.setDiagnostics(diag); asserts.add(schematronAssert); }); - - schematronFile.setAsserts(asserts); - - return schematronFile; + return asserts; } private static void handleError(IError error, Path schematronFilePath) { diff --git a/src/test/resources/eforms-sdk-tests/tedefo-2684/invalid/schematrons/dynamic/validation-stage-1a.sch b/src/test/resources/eforms-sdk-tests/tedefo-2684/invalid/schematrons/dynamic/validation-stage-1a.sch index 9ab9877..9903232 100644 --- a/src/test/resources/eforms-sdk-tests/tedefo-2684/invalid/schematrons/dynamic/validation-stage-1a.sch +++ b/src/test/resources/eforms-sdk-tests/tedefo-2684/invalid/schematrons/dynamic/validation-stage-1a.sch @@ -1,7 +1,7 @@ - + rule|text|P-0001 diff --git a/src/test/resources/eforms-sdk-tests/tedefo-2684/invalid/schematrons/dynamic/validation-stage-1b-1.sch b/src/test/resources/eforms-sdk-tests/tedefo-2684/invalid/schematrons/dynamic/validation-stage-1b-1.sch index ead1ae9..7eb22e6 100644 --- a/src/test/resources/eforms-sdk-tests/tedefo-2684/invalid/schematrons/dynamic/validation-stage-1b-1.sch +++ b/src/test/resources/eforms-sdk-tests/tedefo-2684/invalid/schematrons/dynamic/validation-stage-1b-1.sch @@ -2,7 +2,7 @@ - rule|text|ND-BusinessParty-1 + rule|text|ND-BusinessParty-1 rule|text|ND-ContractingParty-1 rule|text|ND-GazetteReference-1 rule|text|ND-OperationType-1 @@ -13,7 +13,7 @@ rule|text|ND-SenderContact-1 - rule|text|ND-Buyer-1 + rule|text|ND-Buyer-1 rule|text|ND-ProcedureValueEstimate-1 diff --git a/src/test/resources/eforms-sdk-tests/tedefo-2684/invalid/schematrons/dynamic/validation-stage-1b-16.sch b/src/test/resources/eforms-sdk-tests/tedefo-2684/invalid/schematrons/dynamic/validation-stage-1b-16.sch index 6d8e46d..55a1cca 100644 --- a/src/test/resources/eforms-sdk-tests/tedefo-2684/invalid/schematrons/dynamic/validation-stage-1b-16.sch +++ b/src/test/resources/eforms-sdk-tests/tedefo-2684/invalid/schematrons/dynamic/validation-stage-1b-16.sch @@ -2,8 +2,8 @@ - rule|text|ND-BusinessParty-16 - rule|text|ND-ContractingParty-16 + rule|text|ND-BusinessParty-16 + rule|text|ND-ContractingParty-16 rule|text|ND-GazetteReference-16 rule|text|ND-OperationType-16 rule|text|ND-Part-16 @@ -19,7 +19,7 @@ rule|text|ND-LotProcurementScope-16 rule|text|ND-LotTenderingProcess-16 - rule|text|ND-LotTenderingTerms-16 + rule|text|ND-LotTenderingTerms-16 rule|text|ND-AuctionTerms-16 diff --git a/src/test/resources/eforms-sdk-tests/tedefo-2684/valid/schematrons/dynamic/validation-stage-1b-1.sch b/src/test/resources/eforms-sdk-tests/tedefo-2684/valid/schematrons/dynamic/validation-stage-1b-1.sch index e51be47..7eb22e6 100644 --- a/src/test/resources/eforms-sdk-tests/tedefo-2684/valid/schematrons/dynamic/validation-stage-1b-1.sch +++ b/src/test/resources/eforms-sdk-tests/tedefo-2684/valid/schematrons/dynamic/validation-stage-1b-1.sch @@ -2,7 +2,7 @@ - rule|text|ND-BusinessParty-1 + rule|text|ND-BusinessParty-1 rule|text|ND-ContractingParty-1 rule|text|ND-GazetteReference-1 rule|text|ND-OperationType-1 diff --git a/src/test/resources/eforms-sdk-tests/tedefo-2684/valid/schematrons/dynamic/validation-stage-1b-16.sch b/src/test/resources/eforms-sdk-tests/tedefo-2684/valid/schematrons/dynamic/validation-stage-1b-16.sch index 67d8951..fe2bc5c 100644 --- a/src/test/resources/eforms-sdk-tests/tedefo-2684/valid/schematrons/dynamic/validation-stage-1b-16.sch +++ b/src/test/resources/eforms-sdk-tests/tedefo-2684/valid/schematrons/dynamic/validation-stage-1b-16.sch @@ -2,7 +2,7 @@ - rule|text|ND-BusinessParty-16 + rule|text|ND-BusinessParty-16 rule|text|ND-ContractingParty-16 rule|text|ND-GazetteReference-16 rule|text|ND-OperationType-16 diff --git a/src/test/resources/eu/europa/ted/eforms/sdk/analysis/cucumber/tedefo-2684.feature b/src/test/resources/eu/europa/ted/eforms/sdk/analysis/cucumber/tedefo-2684.feature index 4f9aa4f..945979b 100644 --- a/src/test/resources/eu/europa/ted/eforms/sdk/analysis/cucumber/tedefo-2684.feature +++ b/src/test/resources/eu/europa/ted/eforms/sdk/analysis/cucumber/tedefo-2684.feature @@ -19,7 +19,7 @@ Feature: Schematron files - Assert id validation When I load all schematron files And I execute validation Then Rule "" should have been fired - And I should get 2 SDK validation errors + And I should get 3 SDK validation errors Examples: | expected rule |