1
0
Files
Rihards 9e67e74b1f 0.1.0: Funkciju, darbu un kompetenču reģistrs — 95 iestādes no Nolikumi-as-Code@99b5d2e
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
2026-10-24 23:20:00 +00:00

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()