', p)[1:]:
+ gn = int(one(r'
(\d+)\.', g))
+ gid = f"{doc_id}.m{gn}"
+ out += [f'
',
+ el("Title", text(one(r"(.*?)
", g)), 6),
+ el("Description", text(one(r"\s*(.*?)
", g)), 6)]
+ for a in re.finditer(r'(.*?)\n\s*
\s*(?=\s*
)', g, re.S):
+ an, body = int(a.group(1)), a.group(2)
+ aid = f"{doc_id}.r{an:02d}"
+ action_ids.add(an)
+ printed = text(one(r'(.*?)', body))
+ assert printed == f"Rīcība {an}", (printed, an)
+ dl = text(one(r'(.*?)', re.sub(r"", "", body, flags=re.S)))
+ out.append(f' ')
+ for t in re.finditer(r'(.*?)', body):
+ out.append(el("Tag", text(t.group(2)), 8,
+ kind="parvaldibas-rekomendacija" if t.group(1) else None))
+ out += [el("Title", text(one(r"(.*?)
", body)), 8),
+ el("Text", text(one(r'(.*?)
', body)), 8),
+ el("Measurement", text(re.sub(r".*?", "",
+ one(r'(.*?)
', body), count=1)), 8),
+ el("Deadline", dl, 8, value=date_iso(dl))]
+ for r in re.findall(r'(.*?)
', body, re.S):
+ t = text(r)
+ kind = {"Saistīts ar:": "saistits", "Avots:": "avots", "Piemērs:": "piemers"}
+ k = next((v for p_, v in kind.items() if t.startswith(p_)), None)
+ if k:
+ t = t.split(":", 1)[1].strip()
+ hrefs = " ".join(absurl(u) for u in re.findall(r'href="([^"]+)"', r))
+ nums = re.findall(r"Rīcība (\d+)", t)
+ refs_all.append((an, nums))
+ acts = " ".join(f"{doc_id}.r{int(n):02d}" for n in nums)
+ out.append(el("Reference", t, 8, kind=k, actions=acts, href=hrefs))
+ out.append(" ")
+ out.append(" ")
+ out.append(" ")
+ xml_p += out
+
+ # --- Principi ---
+ pr_sec = one(r'id="principi">(.*?)
', h)
+ pr_intro = text(one(r'
(.*?)
', pr_sec))
+ xml_pr = ['
', el("Heading", text(one(r"^(.*?)", pr_sec)), 4),
+ el("Intro", pr_intro, 4)]
+ for i, b in enumerate(re.findall(r'(.*?)
', pr_sec, re.S), 1):
+ xml_pr += [f' ',
+ el("Label", text(one(r'(.*?)
', b)), 6),
+ el("Text", text(one(r'\s*(.*?)
', b)), 6),
+ " "]
+ xml_pr.append(" ")
+
+ # --- Saņemtie priekšlikumi ---
+ pk = one(r'id="priekslikumi">.*?
(.*?)
', h)
+ pk_nums = sorted({int(n) for n in re.findall(r"\((?:Rīcība )?(\d+)\)", text(pk))})
+ xml_pk = [el("ProposalsNote", text(pk), 2,
+ actions=" ".join(f"{doc_id}.r{n:02d}" for n in pk_nums))]
+
+ # --- Starptautiskā pieredze ---
+ xml_rs = ["
"]
+ for i, c in enumerate(re.findall(r'(.*?)
', h, re.S), 1):
+ xml_rs += [f' ',
+ el("Country", text(one(r'(.*?)
', c)), 6),
+ el("Title", text(one(r"(.*?)
", c)), 6),
+ el("Text", text(one(r"\s*(.*?)
", c)), 6),
+ " "]
+ xml_rs.append(" ")
+
+ # --- Pārbaudes ---
+ expect = set(range(1, max(action_ids) + 1))
+ missing = expect - action_ids
+ bad = [(a, n) for a, ns in refs_all for n in ns if int(n) not in action_ids]
+ print(f"{doc_id}: {len(pillars)} pīlāri, {len(action_ids)} rīcības; trūkst {sorted(missing) or '—'}; "
+ f"nederīgas atsauces {bad or '—'}")
+
+ head = [
+ '',
+ f'
',
+ el("Title", title, 2),
+ el("Author", "PPP Asociācija (PPPA)", 2),
+ el("Status", status, 2),
+ el("Updated", upd + ".", 2, value=date_iso(upd)),
+ el("ProposalsOpened", intake + ".", 2, value=date_iso(intake)),
+ el("SourceUrl", "https://pppa.lv/mi-strategija", 2),
+ " " + "".join(el("Word", w, 0) for w in slogan) + "",
+ el("Vision", vision, 2),
+ ]
+ xml = "\n".join(head + xml_p + xml_pr + xml_pk + xml_rs + ["", ""])
+ out = Path(out_dir) / f"{doc_id}.xml"
+ out.parent.mkdir(parents=True, exist_ok=True)
+ out.write_text(xml, encoding="utf-8")
+ print("->", out)
+
+
+if __name__ == "__main__":
+ main(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else "data")
diff --git a/tools/validate.py b/tools/validate.py
new file mode 100644
index 0000000..500076c
--- /dev/null
+++ b/tools/validate.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+"""Pārbauda MI stratēģijas datukopu: XSD, faila nosaukums = ID, numerācija.
+
+Lietojums: python3 tools/validate.py [data/]
+Prasības: pip install lxml
+"""
+import sys
+from pathlib import Path
+from lxml import etree
+
+ROOT = Path(__file__).resolve().parent.parent
+XSD = etree.XMLSchema(etree.parse(str(ROOT / "schemas" / "mi-strategija-0.1.xsd")))
+NS = {"s": "urn:pppa:cac:mi-strategija:0.1"}
+
+
+def check(path):
+ errs = []
+ doc = etree.parse(str(path))
+ if not XSD.validate(doc):
+ errs += [f"XSD {e.line}: {e.message}" for e in XSD.error_log]
+ return errs
+ r = doc.getroot()
+ did = r.get("id")
+ if path.stem != did:
+ errs.append(f"faila nosaukums {path.name} ≠ ID {did}.xml")
+ if r.find("s:Updated", NS).get("value") != did[-10:]:
+ errs.append("ID datums nesakrīt ar Updated/@value")
+ for p in r.iterfind("s:Pillar", NS):
+ if not p.get("id").startswith(did + ".p"):
+ errs.append(f"pīlāra ID {p.get('id')}")
+ nums = []
+ for a in r.iterfind(".//s:Action", NS):
+ n = int(a.get("number"))
+ nums.append(n)
+ if a.get("id") != f"{did}.r{n:02d}":
+ errs.append(f"rīcības {n} ID {a.get('id')} neatbilst numuram")
+ if sorted(nums) != list(range(1, len(nums) + 1)):
+ errs.append(f"rīcību numerācija nav 1..{len(nums)}: {sorted(nums)}")
+ goals = [int(g.get("number").rstrip(".")) for g in r.iterfind(".//s:Goal", NS)]
+ if goals != list(range(1, len(goals) + 1)):
+ errs.append(f"mērķu numerācija {goals}")
+ nores = [a.get("number") for a in r.iterfind(".//s:Action", NS) if a.find("s:Responsible", NS) is None]
+ print(f" {path.name}: {len(list(r.iterfind('s:Pillar', NS)))} pīlāri, {len(goals)} mērķi, "
+ f"{len(nums)} rīcības; bez atbildīgās institūcijas: {len(nores)}")
+ return errs
+
+
+def main(folder):
+ bad = 0
+ for f in sorted(Path(folder).glob("pppa-mis-*.xml")):
+ e = check(f)
+ for x in e:
+ print(" KĻŪDA", f.name, x)
+ bad += bool(e)
+ print("OK" if not bad else f"{bad} faili ar kļūdām")
+ return 1 if bad else 0
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1] if len(sys.argv) > 1 else ROOT / "data"))