Shēma registrs-0.1.xsd; iestades/<VPK ID>/{funkcijas,darbi,kompetence}.xml un registrs/ apvienojums.
656 funkcijas, 1585 darbi, 664 kompetences; VARAM funkciju formulējumi gramatiski saskaņoti (ai_proposed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016igpMJBtapmG6vHE4vSF9q
71 lines
3.1 KiB
Python
71 lines
3.1 KiB
Python
"""FDK reģistra pārbaude: XSD, ID unikalitāte, avotu esamība un pilnums, reģistrs = iestāžu failu apvienojums.
|
|
|
|
python3 tools/validate.py --nolikumi ../Nolikumi-as-Code
|
|
"""
|
|
import argparse
|
|
import glob
|
|
import os
|
|
import sys
|
|
|
|
from lxml import etree
|
|
|
|
NS = "{urn:pppa:vpk:nolikums:0.1}"
|
|
FNS = "{urn:pppa:vpk:fdk:0.1}"
|
|
FILES = ("funkcijas.xml", "darbi.xml", "kompetence.xml")
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--nolikumi", required=True)
|
|
a = ap.parse_args()
|
|
schema = etree.XMLSchema(etree.parse("schemas/registrs-0.1.xsd"))
|
|
errors, ids, by_file = [], {}, {}
|
|
points, must = set(), set()
|
|
for f in glob.glob(os.path.join(a.nolikumi, "data", "*.xml")):
|
|
for p in etree.parse(f).getroot().iter(NS + "Point"):
|
|
points.add(p.get("id"))
|
|
t = (p.findtext(NS + "Text") or "").strip().lower()
|
|
if p.get("kind") in ("function", "task", "right") and not t.startswith("(svītrots"):
|
|
must.add(p.get("id"))
|
|
used = {}
|
|
for path in sorted(glob.glob("iestades/*/*.xml")) + sorted(glob.glob("registrs/*.xml")):
|
|
doc = etree.parse(path)
|
|
if not schema.validate(doc):
|
|
errors += [f"{path}: {e.message}" for e in schema.error_log][:5]
|
|
recs = [e for e in doc.getroot() if isinstance(e.tag, str)]
|
|
by_file[path] = {e.get("id") for e in recs}
|
|
if path.startswith("iestades/"):
|
|
org = path.split("/")[1]
|
|
for e in recs:
|
|
i, av = e.get("id"), e.get("avots")
|
|
if i in ids:
|
|
errors.append(f"{i}: divreiz ({ids[i]}, {path})")
|
|
ids[i] = path
|
|
if e.get("iestāde") != org or i[2:9] != org:
|
|
errors.append(f"{i}: iestāde nesakrīt ar mapi {org}")
|
|
if av not in points:
|
|
errors.append(f"{i}: avots {av} nav Nolikumi-as-Code")
|
|
if av in used:
|
|
errors.append(f"{av}: izmantots divreiz ({used[av]}, {i})")
|
|
used[av] = i
|
|
if not (e.findtext(FNS + "Formulējums") or "").strip():
|
|
errors.append(f"{i}: tukšs formulējums")
|
|
built = {os.path.basename(d) for d in glob.glob("iestades/*")}
|
|
must = {m for m in must if m[7:14] in built} # tikai iestādes, kas ir uzbūvētas
|
|
missing = sorted(must - set(used))
|
|
errors += [f"{m}: funkcijas/uzdevuma/tiesību punkts nav reģistrā" for m in missing[:20]]
|
|
for fn in FILES:
|
|
inst = set().union(*[v for k, v in by_file.items() if k.startswith("iestades/") and k.endswith("/" + fn)] or [set()])
|
|
if f"registrs/{fn}" in by_file and by_file[f"registrs/{fn}"] != inst:
|
|
errors.append(f"registrs/{fn}: nesakrīt ar iestāžu failu apvienojumu")
|
|
n = {fn: sum(len(v) for k, v in by_file.items() if k.startswith("iestades/") and k.endswith("/" + fn)) for fn in FILES}
|
|
print(f"{len(by_file)} faili, {len(ids)} ieraksti {n}; obligātie punkti {len(must)}, iztrūkst {len(missing)}")
|
|
if errors:
|
|
print("\n".join(errors[:60]))
|
|
sys.exit(1)
|
|
print("OK")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|