Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 European Union
* Copyright 2025 European Union
*
* Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European
* Commission – subsequent versions of the EUPL (the "Licence"); You may not use this work except in
Expand All @@ -13,21 +13,121 @@
*/
package eu.europa.ted.eforms.sdk.schematron;

import java.util.List;

import eu.europa.ted.efx.model.Context;
import eu.europa.ted.efx.model.rules.RuleNature;
import eu.europa.ted.efx.model.rules.RuleSeverity;
import eu.europa.ted.efx.model.rules.ValidationRule;
import eu.europa.ted.efx.model.variables.DynamicVariable;

/**
* Represents a Schematron <assert> element.
* Fires when the test expression evaluates to false.
* For rules referencing dynamic variables, the test is guarded so that API errors
* do not cause the main rule to fire — a companion {@link NoApiError} assert handles that.
*/
public class SchematronAssert extends SchematronTest {

public SchematronAssert(ValidationRule rule, Context ruleContext) {
private final List<DynamicVariable> dynamicVariables;

public SchematronAssert(final ValidationRule rule, final Context ruleContext) {
super(rule, ruleContext);
this.dynamicVariables = rule.findReferencedDynamicVariables();
}

@Override
public RuleNature getRuleNature() {
if (!this.dynamicVariables.isEmpty()) {
return RuleNature.DYNAMIC;
}
return super.getRuleNature();
}

@Override
public String getElementName() {
return "assert";
}

@Override
public String getTest() {
String baseTest = super.getTest();
if (this.getRuleNature() != RuleNature.DYNAMIC) {
return baseTest;
}
// An assert fires when the test is false. Prepending "($varName = -1) or" makes the
// test true when any dynamic variable errored, preventing the main assert from firing.
// Companion NoApiError asserts handle API errors separately.
StringBuilder sb = new StringBuilder();
for (var dynamicVar : this.dynamicVariables) {
sb.append("($").append(dynamicVar.name).append(" = -1) or ");
}
for (var variable : this.rule.getAutoGeneratedVariables()) {
sb.append("($").append(variable.name).append(" = -1) or ");
}
if (this.rule.getCondition() != null) {
// WHEN clause: combineWithOrParenthesized already wrapped each operand in parens.
sb.append(baseTest);
} else {
// No WHEN clause: the raw expression needs wrapping to isolate it from the guards.
sb.append("(").append(baseTest).append(")");
}
return sb.toString();
}

/**
* A companion Schematron &lt;assert&gt; that checks a dynamic variable did not return an error (-1).
* Generated for each dynamic variable (declared or auto-generated) referenced by a rule.
*/
public static class NoApiError extends SchematronAssert {

private final DynamicVariable dynamicVariable;

public NoApiError(ValidationRule rule, DynamicVariable dynamicVariable, Context ruleContext) {
super(rule, ruleContext);
this.dynamicVariable = dynamicVariable;
}

@Override
public RuleNature getRuleNature() {
return RuleNature.DYNAMIC;
}

@Override
public SchematronLet getLetElement() {
if (this.dynamicVariable instanceof DynamicVariable.AutoGenerated) {
return new SchematronLet(this.dynamicVariable);
}
return null;
}

@Override
public String getId() {
return this.rule.getId() + "-api-error-" + this.dynamicVariable.identity();
}

@Override
public String getRole() {
return this.dynamicVariable.errorSeverity().toString().toUpperCase();
}

@Override
public String getTest() {
return "not($" + this.dynamicVariable.name + " = -1)";
}

@Override
public String getMessage() {
if (this.dynamicVariable.errorLabel() != null) {
return this.dynamicVariable.errorLabel();
}
return this.dynamicVariable.errorSeverity() == RuleSeverity.WARNING
? "rule|text|api-warning" : "rule|text|api-error";
}

@Override
public SchematronDiagnostic getDiagnostic() {
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 European Union
* Copyright 2025 European Union
*
* Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European
* Commission – subsequent versions of the EUPL (the "Licence"); You may not use this work except in
Expand Down
Loading
Loading