From f07bac76cf5268033ad9489e123c3f9ace7d6dfe Mon Sep 17 00:00:00 2001 From: bananas-n-apples Date: Wed, 18 Feb 2026 21:26:29 +0530 Subject: [PATCH 1/4] added a basic version of rule 4.2.1.1 from the AF specification --- validation/rules/sbgn_af.sch | 43 +++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/validation/rules/sbgn_af.sch b/validation/rules/sbgn_af.sch index 759d648..29da2bb 100755 --- a/validation/rules/sbgn_af.sch +++ b/validation/rules/sbgn_af.sch @@ -34,6 +34,10 @@ Schematron validation for SBGN AF + + + + This assertion should always fail. @@ -94,7 +98,7 @@ Schematron validation for SBGN AF id="af10102" name="check-positive-influence-target-class" role="error" - see="sbgn-af-L1V1.0-3.3.1" + see="sbgn-af-L1V1.2-4.2.1.1" test=" $target-class='biological activity' or $target-class='phenotype'" @@ -259,6 +263,43 @@ Schematron validation for SBGN AF + + + + + Illegal overlapping nodes are not allowed in SBGN AF. + + + From e96d7c8109d2f1dbf77fce14b98f63323a327598 Mon Sep 17 00:00:00 2001 From: bananas-n-apples Date: Fri, 20 Feb 2026 11:18:57 +0530 Subject: [PATCH 2/4] fixed issues in the validation for the new layout rule and added the testfiles --- .../error-test-files/AF/af10115-fail.sbgn | 30 +++++++++++++++++++ .../error-test-files/AF/af10115-pass.sbgn | 26 ++++++++++++++++ validation/rules/sbgn_af.sch | 14 ++++----- 3 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 validation/error-test-files/AF/af10115-fail.sbgn create mode 100644 validation/error-test-files/AF/af10115-pass.sbgn diff --git a/validation/error-test-files/AF/af10115-fail.sbgn b/validation/error-test-files/AF/af10115-fail.sbgn new file mode 100644 index 0000000..8a42f6b --- /dev/null +++ b/validation/error-test-files/AF/af10115-fail.sbgn @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/validation/error-test-files/AF/af10115-pass.sbgn b/validation/error-test-files/AF/af10115-pass.sbgn new file mode 100644 index 0000000..8adfb86 --- /dev/null +++ b/validation/error-test-files/AF/af10115-pass.sbgn @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/validation/rules/sbgn_af.sch b/validation/rules/sbgn_af.sch index 29da2bb..8a52fbc 100755 --- a/validation/rules/sbgn_af.sch +++ b/validation/rules/sbgn_af.sch @@ -32,12 +32,11 @@ Schematron validation for SBGN AF - - - + + This assertion should always fail. @@ -289,11 +288,12 @@ Schematron validation for SBGN AF @class = 'delay') and @class != 'unit of information' and ( - (@x <= current()/@x + current()/@width) - and (@x + @width >= current()/@x) - and (@y <= current()/@y + current()/@height) - and (@y + @height >= current()/@y) + (number(sbgn:bbox/@x) <= number(current()/sbgn:bbox/@x) + number(current()/sbgn:bbox/@w)) and + (number(sbgn:bbox/@x) + number(sbgn:bbox/@w) >= number(current()/sbgn:bbox/@x)) and + (number(sbgn:bbox/@y) <= number(current()/sbgn:bbox/@y) + number(current()/sbgn:bbox/@h)) and + (number(sbgn:bbox/@y) + number(sbgn:bbox/@h) >= number(current()/sbgn:bbox/@y)) ) + ] )" diagnostics="id">Illegal overlapping nodes are not allowed in SBGN AF. From fb1e9295ea2b4ee5fe382a966b2194af9c587f82 Mon Sep 17 00:00:00 2001 From: bananas-n-apples Date: Fri, 20 Feb 2026 12:26:13 +0530 Subject: [PATCH 3/4] fixed typo I introduced into the file --- validation/rules/sbgn_af.sch | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/validation/rules/sbgn_af.sch b/validation/rules/sbgn_af.sch index 8a52fbc..515c94d 100755 --- a/validation/rules/sbgn_af.sch +++ b/validation/rules/sbgn_af.sch @@ -35,8 +35,6 @@ Schematron validation for SBGN AF - - This assertion should always fail. @@ -97,7 +95,7 @@ Schematron validation for SBGN AF id="af10102" name="check-positive-influence-target-class" role="error" - see="sbgn-af-L1V1.2-4.2.1.1" + see="sbgn-af-L1V1.0-3.3.1" test=" $target-class='biological activity' or $target-class='phenotype'" From 253f515d46a41fa5bced47c830eeeb057ba6a94d Mon Sep 17 00:00:00 2001 From: bananas-n-apples Date: Sun, 22 Feb 2026 12:18:10 +0530 Subject: [PATCH 4/4] improved rule af10115 and added validate.py. updated the failing testfile. --- .../error-test-files/AF/af10115-fail.sbgn | 23 +--- validation/rules/sbgn_af.sch | 3 +- validation/validate.py | 124 ++++++++++++++++++ 3 files changed, 128 insertions(+), 22 deletions(-) create mode 100644 validation/validate.py diff --git a/validation/error-test-files/AF/af10115-fail.sbgn b/validation/error-test-files/AF/af10115-fail.sbgn index 8a42f6b..76daaf7 100644 --- a/validation/error-test-files/AF/af10115-fail.sbgn +++ b/validation/error-test-files/AF/af10115-fail.sbgn @@ -1,30 +1,13 @@ - + - - - - - - + - - - - - - - - diff --git a/validation/rules/sbgn_af.sch b/validation/rules/sbgn_af.sch index 515c94d..5e45832 100755 --- a/validation/rules/sbgn_af.sch +++ b/validation/rules/sbgn_af.sch @@ -276,7 +276,7 @@ Schematron validation for SBGN AF id="af10115" name="check-overlapping-nodes" role="error" - test="not(following::sbgn:glyph[ + test="not(following-sibling::sbgn:glyph[ (@class= 'biological activity' or @class = 'phenotype' or @class = 'submap' or @@ -284,7 +284,6 @@ Schematron validation for SBGN AF @class = 'or' or @class = 'not' or @class = 'delay') - and @class != 'unit of information' and ( (number(sbgn:bbox/@x) <= number(current()/sbgn:bbox/@x) + number(current()/sbgn:bbox/@w)) and (number(sbgn:bbox/@x) + number(sbgn:bbox/@w) >= number(current()/sbgn:bbox/@x)) and diff --git a/validation/validate.py b/validation/validate.py new file mode 100644 index 0000000..4d45b97 --- /dev/null +++ b/validation/validate.py @@ -0,0 +1,124 @@ +import subprocess +from pathlib import Path + +# -------------------- +# Global configuration +# -------------------- + +SAXON_JAR = Path("lib/saxon9he.jar") +SCHEMATRON_DIR = Path("schematron") +RULES_DIR = Path("rules") +TESTS_DIR = Path("error-test-files") +SVRL_ROOT = Path("svrl") + + +# -------------------- +# Utility +# -------------------- + +def run(cmd): + print("▶", " ".join(cmd)) + subprocess.run(cmd, check=True) + + +# -------------------- +# Compile step +# -------------------- + +def compile_schematron(language: str): + """ + Compile Schematron rules for a given SBGN language (pd / er / af) + into an XSLT validator. + """ + language = language.lower() + + sch_file = RULES_DIR / f"sbgn_{language}.sch" + step1 = Path(f"sbgn_{language}.step1.sch") + step2 = Path(f"sbgn_{language}.step2.sch") + validator = Path(f"sbgn_{language}_validator.xsl") + + print(f"\n=== Compiling Schematron for {language.upper()} ===") + + # Step 1: expand includes + run([ + "java", "-jar", str(SAXON_JAR), + "-s:" + str(sch_file), + "-xsl:" + str(SCHEMATRON_DIR / "iso_dsdl_include.xsl"), + "-o:" + str(step1) + ]) + + # Step 2: expand abstract patterns + run([ + "java", "-jar", str(SAXON_JAR), + "-s:" + str(step1), + "-xsl:" + str(SCHEMATRON_DIR / "iso_abstract_expand.xsl"), + "-o:" + str(step2) + ]) + + # Step 3: compile to SVRL-producing XSLT + run([ + "java", "-jar", str(SAXON_JAR), + "-s:" + str(step2), + "-xsl:" + str(SCHEMATRON_DIR / "iso_svrl_for_xslt1.xsl"), + "-o:" + str(validator) + ]) + + print(f" Validator created: {validator}") + return validator + + +# -------------------- +# Validation step +# -------------------- + +def validate_sbgn(language: str, sbgn_file: Path): + """ + Validate a single SBGN file and write SVRL output. + """ + language = language.upper() + + validator = Path(f"sbgn_{language.lower()}_validator.xsl") + svrl_dir = SVRL_ROOT / language + svrl_dir.mkdir(parents=True, exist_ok=True) + + output = svrl_dir / (sbgn_file.stem + ".svrl") + + print(f"\n=== Validating {sbgn_file.name} ({language}) ===") + + run([ + "java", "-jar", str(SAXON_JAR), + "-s:" + str(sbgn_file), + "-xsl:" + str(validator), + "-o:" + str(output) + ]) + + print(f"SVRL written to {output}") + + +# -------------------- +# Batch validation +# -------------------- + +def validate_all(language: str): + """ + Validate all test files for a given language. + """ + language = language.upper() + test_dir = TESTS_DIR / language + + for sbgn in sorted(test_dir.glob("*.sbgn")): + validate_sbgn(language, sbgn) + + +# -------------------- +# Entry point +# -------------------- + +if __name__ == "__main__": + + pd = "pd" + af = "af" + er = "er" + #compile_schematron(pd) + compile_schematron(af) + validate_all(af)