625 lines
24 KiB
Python
625 lines
24 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
xsd_til_yaml.py
|
||
|
||
Genererer YAML-skelet fra en XSD-fil til brug med udpak_semistruktur.
|
||
|
||
Producerer:
|
||
- skabeloner.yaml – feltskabeloner for alle navngivne complexTypes
|
||
- nøgler.yaml – nøgle-placeholders for overliggende liste-niveauer
|
||
- udtræk_<navn>.yaml – én fil per maxOccurs > 1 element
|
||
- config_<navn>.yaml – hoved-config der inkluderer alle filer
|
||
|
||
Kør med:
|
||
python3 xsd_til_yaml.py --config xsd_til_yaml_config.yaml
|
||
"""
|
||
|
||
from email import parser
|
||
import os
|
||
import argparse
|
||
from xml.etree import ElementTree as ET
|
||
|
||
from schema_dataklasser import XsdFelt, XsdSkabelonRef, XsdKompleksType, XsdListeElement
|
||
|
||
XS_NS = "http://www.w3.org/2001/XMLSchema"
|
||
|
||
|
||
# ============================================================
|
||
# Fase 1: Hjælpefunktioner
|
||
# ============================================================
|
||
def _byg_choice_søskende_index(liste_elementer: list) -> dict[str, list[str]]:
|
||
"""
|
||
Returnerer dict: element_navn → liste af rod_stier
|
||
for elementer der forekommer i flere choice-grene.
|
||
"""
|
||
fra_navn: dict[str, list[str]] = {}
|
||
for el in liste_elementer:
|
||
fra_navn.setdefault(el.element_navn, []).append(el.rod_sti)
|
||
# Behold kun dem der har mere end én sti
|
||
return {navn: stier for navn, stier in fra_navn.items() if len(stier) > 1}
|
||
|
||
|
||
def _find_namespaces(xsd_sti: str) -> dict[str, str]:
|
||
"""Læser alle namespace-deklarationer fra XSD-filen."""
|
||
namespaces = {}
|
||
for event, elem in ET.iterparse(xsd_sti, events=["start-ns"]):
|
||
prefix, uri = elem
|
||
namespaces[prefix] = uri
|
||
return namespaces
|
||
|
||
|
||
def _byg_xs_tag(lokalt_navn: str) -> str:
|
||
"""Bygger fuldt kvalificeret XS-tag."""
|
||
return f"{{{XS_NS}}}{lokalt_navn}"
|
||
|
||
|
||
def _strip_prefix(type_navn: str) -> str:
|
||
"""
|
||
Fjerner namespace-præfiks fra et typenavn.
|
||
'carf:PersonParty_Type' → 'PersonParty_Type'
|
||
'xsd:string' → 'xsd:string' (bevares)
|
||
"""
|
||
if not type_navn or ":" not in type_navn:
|
||
return type_navn
|
||
prefix, lokalt = type_navn.split(":", 1)
|
||
if prefix in ("xs", "xsd"):
|
||
return type_navn
|
||
return lokalt
|
||
|
||
|
||
def _er_xs_type(type_navn: str) -> bool:
|
||
"""True hvis typen er en XSD-standardtype."""
|
||
if not type_navn:
|
||
return False
|
||
return type_navn.startswith("xs:") or type_navn.startswith("xsd:")
|
||
|
||
|
||
def _er_liste(max_occ: str) -> bool:
|
||
"""True hvis maxOccurs > 1."""
|
||
if max_occ == "unbounded":
|
||
return True
|
||
try:
|
||
return int(max_occ) > 1
|
||
except (ValueError, TypeError):
|
||
return False
|
||
|
||
|
||
def _type_til_skabelon_navn(type_navn: str) -> str:
|
||
"""
|
||
'PersonParty_Type' → 'personparty'
|
||
'carf:Address_Type' → 'address'
|
||
"""
|
||
lokalt = _strip_prefix(type_navn)
|
||
return lokalt.replace("_Type", "").replace("Type", "").lower()
|
||
|
||
|
||
# ============================================================
|
||
# Fase 2: Parser
|
||
# ============================================================
|
||
|
||
class XsdParser:
|
||
|
||
def __init__(self, xsd_sti: str):
|
||
self.xsd_sti = xsd_sti
|
||
self.tree = ET.parse(xsd_sti)
|
||
self.root = self.tree.getroot()
|
||
self.namespaces = _find_namespaces(xsd_sti)
|
||
self.ns_url_til_prefix = {v: k for k, v in self.namespaces.items()}
|
||
self.target_ns = self.root.get("targetNamespace", "")
|
||
self.komplekse_typer: dict[str, XsdKompleksType] = {}
|
||
self.liste_elementer: list[XsdListeElement] = []
|
||
self.choice_elementer: list = [] # ← tilføj denne linje
|
||
|
||
def _xs(self, navn: str) -> str:
|
||
return _byg_xs_tag(navn)
|
||
|
||
def _er_intern_type(self, type_navn: str) -> bool:
|
||
if not type_navn or _er_xs_type(type_navn):
|
||
return False
|
||
if ":" not in type_navn:
|
||
return True
|
||
prefix = type_navn.split(":")[0]
|
||
return self.namespaces.get(prefix, "") == self.target_ns
|
||
|
||
def parse(self, min_felter: int = 1) -> None:
|
||
self._registrer_eksterne_typer()
|
||
self._parse_alle_komplekse_typer()
|
||
self._find_liste_elementer(min_felter)
|
||
# Kør skabelon-parsing igen nu vi ved hvilke elementer der har egne filer
|
||
self._parse_alle_komplekse_typer()
|
||
self._registrer_choice_elementer()
|
||
|
||
def _registrer_eksterne_typer(self) -> None:
|
||
for import_node in self.root.findall(self._xs("import")):
|
||
ns_url = import_node.get("namespace", "")
|
||
schema_sti = import_node.get("schemaLocation", "")
|
||
if schema_sti:
|
||
import_sti = os.path.join(
|
||
os.path.dirname(self.xsd_sti), schema_sti
|
||
)
|
||
if os.path.exists(import_sti):
|
||
self._parse_importeret_fil(import_sti)
|
||
continue
|
||
prefix = self.ns_url_til_prefix.get(ns_url, "")
|
||
print(f" Info: Ekstern namespace '{prefix}' ({ns_url}) – "
|
||
f"kan ikke læse felter")
|
||
|
||
def _parse_importeret_fil(self, sti: str) -> None:
|
||
try:
|
||
root = ET.parse(sti).getroot()
|
||
except Exception as e:
|
||
print(f" Advarsel: Kunne ikke parse '{sti}': {e}")
|
||
return
|
||
|
||
# Pas 1: registrer alle typenavne
|
||
for ct in root.findall(self._xs("complexType")):
|
||
navn = ct.get("name")
|
||
if navn and navn not in self.komplekse_typer:
|
||
self.komplekse_typer[navn] = XsdKompleksType(navn=navn, er_ekstern=False)
|
||
|
||
# Pas 2: udpak felter – to gange så forward-references løses
|
||
for _ in range(2):
|
||
for ct in root.findall(self._xs("complexType")):
|
||
navn = ct.get("name")
|
||
if not navn:
|
||
continue
|
||
kt = self.komplekse_typer[navn]
|
||
kt.felter = self._udpak_felter(ct)
|
||
if ct.find(self._xs("simpleContent")) is not None:
|
||
kt.har_tekst = True
|
||
# Omdøb #text til type-navnet
|
||
type_basis = navn.replace("_Type", "").replace("Type", "").lower()
|
||
for felt in kt.felter:
|
||
if isinstance(felt, XsdFelt) and felt.navn == "#text":
|
||
print(f" DEBUG omdøb: {navn} #text → {type_basis}, xml_navn={felt.xml_navn}")
|
||
felt.xml_navn = "#text"
|
||
felt.navn = "value" # ← generisk navn
|
||
print(f" DEBUG efter: navn={felt.navn} xml_navn={felt.xml_navn} felt_ref={felt.felt_ref}")
|
||
|
||
# Rekursive imports
|
||
for import_node in root.findall(self._xs("import")):
|
||
schema_sti = import_node.get("schemaLocation", "")
|
||
if schema_sti:
|
||
import_sti = os.path.join(os.path.dirname(sti), schema_sti)
|
||
if os.path.exists(import_sti):
|
||
self._parse_importeret_fil(import_sti)
|
||
|
||
def _parse_alle_komplekse_typer(self) -> None:
|
||
"""To-pas parsing så forward-references løses."""
|
||
# Pas 1: registrer alle typenavne
|
||
for ct in self.root.findall(self._xs("complexType")):
|
||
navn = ct.get("name")
|
||
if navn and navn not in self.komplekse_typer:
|
||
self.komplekse_typer[navn] = XsdKompleksType(navn=navn)
|
||
|
||
# Pas 2: udpak felter – to gange så forward-references løses
|
||
for _ in range(2):
|
||
for ct in self.root.findall(self._xs("complexType")):
|
||
navn = ct.get("name")
|
||
if not navn:
|
||
continue
|
||
kt = self.komplekse_typer[navn]
|
||
kt.felter = self._udpak_felter(ct)
|
||
if ct.find(self._xs("simpleContent")) is not None:
|
||
kt.har_tekst = True
|
||
# Omdøb #text til type-navnet
|
||
type_basis = navn.replace("_Type", "").replace("Type", "").lower()
|
||
for felt in kt.felter:
|
||
if isinstance(felt, XsdFelt) and felt.navn == "#text":
|
||
print(f" DEBUG omdøb: {navn} #text → {type_basis}, xml_navn={felt.xml_navn}")
|
||
felt.xml_navn = "#text"
|
||
felt.navn = "value" # ← generisk navn
|
||
print(f" DEBUG efter: navn={felt.navn} xml_navn={felt.xml_navn} felt_ref={felt.felt_ref}")
|
||
|
||
def _udpak_felter(self, ct_node) -> list:
|
||
"""Koordinator – detekterer XSD-mønster og kalder rette hjælpefunktion."""
|
||
simple = ct_node.find(self._xs("simpleContent"))
|
||
if simple is not None:
|
||
return self._udpak_simple_content(simple)
|
||
|
||
complex_content = ct_node.find(self._xs("complexContent"))
|
||
if complex_content is not None:
|
||
return self._udpak_complex_content(complex_content)
|
||
|
||
felter = self._udpak_sequence_eller_choice(ct_node)
|
||
felter.extend(self._udpak_attributter(ct_node))
|
||
return felter
|
||
|
||
def _udpak_attributter(self, node) -> list:
|
||
felter = []
|
||
for attr in node.findall(self._xs("attribute")):
|
||
navn = attr.get("name")
|
||
if not navn:
|
||
continue
|
||
felter.append(XsdFelt(
|
||
navn=navn,
|
||
er_attribut=True,
|
||
xsd_type=attr.get("type", "xsd:string"),
|
||
påkrævet=attr.get("use") == "required"
|
||
))
|
||
return felter
|
||
|
||
def _udpak_simple_content(self, simple_node, element_navn: str = "#text") -> list:
|
||
felter = []
|
||
ext = simple_node.find(self._xs("extension"))
|
||
if ext is None:
|
||
ext = simple_node.find(self._xs("restriction"))
|
||
if ext is not None:
|
||
felter.append(XsdFelt(
|
||
navn=element_navn, # ← brug element_navn i stedet for #text
|
||
xsd_type=ext.get("base", "xsd:string"),
|
||
påkrævet=True,
|
||
er_tekst=True
|
||
))
|
||
felter.extend(self._udpak_attributter(ext))
|
||
return felter
|
||
|
||
def _udpak_complex_content(self, complex_node) -> list:
|
||
"""Arv via extension/restriction."""
|
||
felter = []
|
||
node = complex_node.find(self._xs("extension"))
|
||
if node is None:
|
||
node = complex_node.find(self._xs("restriction"))
|
||
if node is None:
|
||
return felter
|
||
base_navn = _strip_prefix(node.get("base", ""))
|
||
if base_navn and base_navn in self.komplekse_typer:
|
||
felter.extend(self.komplekse_typer[base_navn].felter)
|
||
felter.extend(self._udpak_sequence_eller_choice(node))
|
||
felter.extend(self._udpak_attributter(node))
|
||
return felter
|
||
|
||
def _udpak_sequence_eller_choice(self, node, prefix: str = "") -> list:
|
||
felter = []
|
||
for seq in node.findall(self._xs("sequence")):
|
||
felter.extend(self._udpak_container(seq, prefix, er_choice=False))
|
||
for choice in node.findall(self._xs("choice")):
|
||
felter.extend(self._udpak_container(choice, prefix, er_choice=True))
|
||
return felter
|
||
|
||
def _udpak_container(self, container, prefix: str = "", er_choice: bool = False) -> list:
|
||
"""Udpakker elementer fra én sequence eller choice."""
|
||
felter = []
|
||
for el in container.findall(self._xs("element")):
|
||
el_navn = el.get("name")
|
||
el_type = el.get("type", "")
|
||
max_occ = el.get("maxOccurs", "1")
|
||
min_occ = el.get("minOccurs", "1")
|
||
er_liste = _er_liste(max_occ)
|
||
påkrævet = min_occ != "0"
|
||
|
||
if not el_navn:
|
||
continue
|
||
|
||
fuldt_navn = f"{prefix}.{el_navn}" if prefix else el_navn
|
||
|
||
# Navngiven kompleks type → XsdSkabelonRef
|
||
if el_type and not _er_xs_type(el_type):
|
||
type_navn_rent = _strip_prefix(el_type)
|
||
kt = self.komplekse_typer.get(type_navn_rent)
|
||
if kt and not kt.er_ekstern:
|
||
felter.append(XsdSkabelonRef(
|
||
element_navn=fuldt_navn,
|
||
skabelon_navn=_type_til_skabelon_navn(el_type),
|
||
er_liste=er_liste,
|
||
påkrævet=påkrævet,
|
||
er_choice=er_choice
|
||
))
|
||
else:
|
||
# Ekstern eller ukendt → simpelt felt
|
||
felter.append(XsdFelt(
|
||
navn=fuldt_navn,
|
||
xsd_type=el_type,
|
||
påkrævet=påkrævet,
|
||
er_liste=er_liste,
|
||
er_choice=er_choice
|
||
))
|
||
continue
|
||
|
||
# Anonym inline complexType
|
||
inline_ct = el.find(self._xs("complexType"))
|
||
if inline_ct is not None:
|
||
sc = inline_ct.find(self._xs("simpleContent"))
|
||
if sc is not None:
|
||
# simpleContent – elementnavnet som prefix
|
||
for felt in self._udpak_simple_content(sc):
|
||
if felt.navn == "#text":
|
||
felt.navn = fuldt_navn # ← brug element-navnet
|
||
felt.er_tekst = False
|
||
else:
|
||
felt.navn = f"{fuldt_navn}_{felt.navn}"
|
||
felt.er_tekst = False
|
||
felter.append(felt)
|
||
else:
|
||
felter.extend(self._udpak_sequence_eller_choice(inline_ct, prefix=fuldt_navn))
|
||
felter.extend(self._udpak_attributter(inline_ct))
|
||
continue
|
||
|
||
# Simpelt xs:-element
|
||
felter.append(XsdFelt(
|
||
navn=fuldt_navn,
|
||
xsd_type=el_type or "xsd:string",
|
||
påkrævet=påkrævet,
|
||
er_liste=er_liste,
|
||
er_choice=er_choice
|
||
))
|
||
|
||
# Nested containers
|
||
for nested_seq in container.findall(self._xs("sequence")):
|
||
felter.extend(self._udpak_container(nested_seq, prefix, er_choice))
|
||
for nested_choice in container.findall(self._xs("choice")):
|
||
felter.extend(self._udpak_container(nested_choice, prefix, er_choice=True))
|
||
|
||
return felter
|
||
|
||
def _find_liste_elementer(self, min_felter: int = 1) -> None:
|
||
rod_el = self.root.find(self._xs("element"))
|
||
if rod_el is None:
|
||
return
|
||
rod_navn = rod_el.get("name", "rod")
|
||
rod_type = rod_el.get("type", "")
|
||
|
||
# Registrer rod-elementet selv som udtræk-punkt
|
||
rod_inline_ct = rod_el.find(self._xs("complexType"))
|
||
|
||
if rod_type:
|
||
inline_felter = []
|
||
elif rod_inline_ct is not None:
|
||
inline_felter = self._udpak_felter(rod_inline_ct)
|
||
else:
|
||
inline_felter = []
|
||
|
||
self.liste_elementer.append(XsdListeElement(
|
||
element_navn=rod_navn,
|
||
type_navn=rod_type,
|
||
rod_sti=rod_navn,
|
||
overliggende=[],
|
||
felter=inline_felter,
|
||
er_simpel=False,
|
||
join_i_skabelon=""
|
||
))
|
||
|
||
# Traverser resten af XSD-træet
|
||
self._traverser(
|
||
node=rod_el,
|
||
sti=[rod_navn],
|
||
overliggende=[],
|
||
type_navn=rod_type,
|
||
min_felter=min_felter
|
||
)
|
||
|
||
def _traverser(self, node, sti, overliggende, type_navn="", min_felter=1) -> None:
|
||
ct_node = self._hent_ct_node(node, type_navn)
|
||
if ct_node is None:
|
||
return
|
||
for tag in [self._xs("sequence"), self._xs("choice")]:
|
||
for container in ct_node.findall(tag):
|
||
self._traverser_container(container, sti, overliggende, min_felter)
|
||
|
||
def _hent_ct_node(self, node, type_navn: str):
|
||
if type_navn:
|
||
navn_rent = _strip_prefix(type_navn)
|
||
for ct in self.root.findall(self._xs("complexType")):
|
||
if ct.get("name") == navn_rent:
|
||
return ct
|
||
return None
|
||
return node.find(self._xs("complexType"))
|
||
|
||
def _traverser_container(self, container, sti, overliggende, min_felter) -> None:
|
||
for el in container.findall(self._xs("element")):
|
||
el_navn = el.get("name")
|
||
el_type = el.get("type", "")
|
||
max_occ = el.get("maxOccurs", "1")
|
||
if not el_navn:
|
||
continue
|
||
ny_sti = sti + [el_navn]
|
||
|
||
if _er_liste(max_occ):
|
||
rod_sti = ".".join(ny_sti)
|
||
inline_felter = []
|
||
inline_ct = el.find(self._xs("complexType"))
|
||
if inline_ct is not None and not el_type:
|
||
inline_felter = self._udpak_felter(inline_ct)
|
||
|
||
antal = self._tæl_felter(el_type, inline_felter)
|
||
er_simpel = antal < min_felter
|
||
join_i = self._find_join_skabelon(overliggende) if er_simpel else ""
|
||
|
||
self.liste_elementer.append(XsdListeElement(
|
||
element_navn=el_navn,
|
||
type_navn=el_type,
|
||
rod_sti=rod_sti,
|
||
overliggende=list(overliggende),
|
||
felter=inline_felter,
|
||
er_simpel=er_simpel,
|
||
join_i_skabelon=join_i
|
||
))
|
||
self._traverser(el, ny_sti, overliggende + [el_navn], el_type, min_felter)
|
||
else:
|
||
inline_ct = el.find(self._xs("complexType"))
|
||
if el_type and not _er_xs_type(el_type):
|
||
self._traverser(el, ny_sti, overliggende, el_type, min_felter)
|
||
elif inline_ct is not None:
|
||
self._traverser(el, ny_sti, overliggende, "", min_felter)
|
||
|
||
for tag in [self._xs("sequence"), self._xs("choice")]:
|
||
for nested in container.findall(tag):
|
||
self._traverser_container(nested, sti, overliggende, min_felter)
|
||
|
||
def _tæl_felter(self, type_navn: str, inline_felter: list) -> int:
|
||
if inline_felter:
|
||
return len(inline_felter)
|
||
if not type_navn or _er_xs_type(type_navn):
|
||
return 1
|
||
kt = self.komplekse_typer.get(_strip_prefix(type_navn))
|
||
if kt:
|
||
if kt.er_ekstern:
|
||
navn = _strip_prefix(type_navn)
|
||
if any(s in navn for s in ("String", "Code", "Enum")) and \
|
||
not any(s in navn for s in ("Party", "Person", "Organisation", "Address")):
|
||
return 1
|
||
return 99
|
||
return len(kt.felter)
|
||
return 1
|
||
|
||
def _find_join_skabelon(self, overliggende: list[str]) -> str:
|
||
if not overliggende:
|
||
return ""
|
||
nærmeste = overliggende[-1]
|
||
for el in self.liste_elementer:
|
||
if el.element_navn == nærmeste and el.type_navn:
|
||
return _type_til_skabelon_navn(el.type_navn)
|
||
return nærmeste.lower()
|
||
|
||
def _registrer_choice_elementer(self) -> None:
|
||
"""Finder alle choice-elementer i liste-elementerne."""
|
||
from schema_dataklasser import XsdChoiceElement
|
||
|
||
for liste_el in self.liste_elementer:
|
||
type_navn_rent = _strip_prefix(liste_el.type_navn) if liste_el.type_navn else ""
|
||
kt = self.komplekse_typer.get(type_navn_rent)
|
||
if not kt or not kt.felter:
|
||
continue
|
||
|
||
# Find alle choice-grupper i skabelonen
|
||
choice_refs = [f for f in kt.felter
|
||
if isinstance(f, XsdSkabelonRef) and f.er_choice]
|
||
if not choice_refs:
|
||
continue
|
||
|
||
# Grupper efter element_navn's rod-del (fx 'UserID')
|
||
grupper: dict[str, list] = {}
|
||
for ref in choice_refs:
|
||
rod = ref.element_navn.split(".")[0] if "." in ref.element_navn else ref.element_navn
|
||
grupper.setdefault(rod, []).append(ref)
|
||
|
||
for rod_navn, refs in grupper.items():
|
||
alternativer = []
|
||
for ref in refs:
|
||
alt_navn = ref.element_navn.split(".")[-1] if "." in ref.element_navn else ref.element_navn
|
||
alt_sti = f"{liste_el.rod_sti}.{ref.element_navn}"
|
||
alternativer.append((alt_navn, ref.skabelon_navn, alt_sti))
|
||
|
||
self.choice_elementer.append(XsdChoiceElement(
|
||
element_navn=rod_navn,
|
||
rod_sti=liste_el.rod_sti,
|
||
overliggende=liste_el.overliggende + [liste_el.element_navn]
|
||
if liste_el.overliggende is not None else [liste_el.element_navn],
|
||
alternativer=alternativer
|
||
))
|
||
# ============================================================
|
||
# CLI og main
|
||
# ============================================================
|
||
|
||
def læs_config_fil(config_sti: str) -> dict:
|
||
import yaml
|
||
if not os.path.exists(config_sti):
|
||
raise FileNotFoundError(f"Config-filen '{config_sti}' findes ikke.")
|
||
with open(config_sti, "r", encoding="utf-8") as f:
|
||
return yaml.safe_load(f) or {}
|
||
|
||
|
||
def byg_argument_parser() -> argparse.ArgumentParser:
|
||
parser = argparse.ArgumentParser(
|
||
description="Genererer YAML-skelet fra XSD til udpak_semistruktur."
|
||
)
|
||
parser.add_argument("--config", help="Sti til xsd_til_yaml_config.yaml")
|
||
parser.add_argument("--xsd", help="Sti til XSD-filen")
|
||
parser.add_argument("--output", help="Output-mappe til YAML-filer")
|
||
parser.add_argument("--prefix", help="Prefix til udtræk-filnavne (standard: udtræk)")
|
||
parser.add_argument("--min_felter", type=int,
|
||
help="Elementer med færre felter foldes ind som join (standard: 1)")
|
||
parser.add_argument("--db_schema", help="Database schema (standard: dbo)")
|
||
parser.add_argument("--tabel_prefix",help="Prefix til tabelnavne")
|
||
parser.add_argument("--output_type", help="Output-type: fil, tabel eller begge (standard: begge)")
|
||
parser.add_argument("--historik", help="Historik-type: t1 eller t2 (standard: t1)")
|
||
return parser
|
||
|
||
|
||
def main():
|
||
parser = byg_argument_parser()
|
||
args = parser.parse_args()
|
||
|
||
cfg = {}
|
||
if args.config:
|
||
cfg = læs_config_fil(args.config)
|
||
|
||
xsd_sti = args.xsd or cfg.get("xsd")
|
||
output = args.output or cfg.get("output")
|
||
prefix = args.prefix or cfg.get("prefix", "udtræk")
|
||
min_felter = args.min_felter or cfg.get("min_felter", 1)
|
||
forkortelser = cfg.get("forkortelser", {})
|
||
db_schema = args.db_schema or cfg.get("db_schema", "dbo")
|
||
tabel_prefix = args.tabel_prefix or cfg.get("tabel_prefix", "")
|
||
output_type = args.output_type or cfg.get("output_type", "begge")
|
||
historik = args.historik or cfg.get("historik", "t1")
|
||
|
||
if not xsd_sti:
|
||
print("FEJL: 'xsd' skal angives – enten i config-fil eller med --xsd")
|
||
return
|
||
if not output:
|
||
print("FEJL: 'output' skal angives – enten i config-fil eller med --output")
|
||
return
|
||
if not os.path.exists(xsd_sti):
|
||
print(f"FEJL: XSD-filen '{xsd_sti}' findes ikke.")
|
||
return
|
||
|
||
os.makedirs(output, exist_ok=True)
|
||
|
||
print(f"Parser XSD: {xsd_sti}")
|
||
if forkortelser:
|
||
print(f"Forkortelser: {len(forkortelser)} defineret")
|
||
|
||
xsd = XsdParser(xsd_sti)
|
||
xsd.parse(min_felter=min_felter)
|
||
|
||
print(f"\nFandt {len(xsd.komplekse_typer)} komplekse typer:")
|
||
for navn, kt in xsd.komplekse_typer.items():
|
||
ekstern = " (ekstern)" if kt.er_ekstern else ""
|
||
print(f" {navn}{ekstern}: {len(kt.felter)} felter")
|
||
|
||
print(f"\nFandt {len(xsd.liste_elementer)} liste-elementer:")
|
||
for el in xsd.liste_elementer:
|
||
simpel = f" [join → {el.join_i_skabelon}]" if el.er_simpel else ""
|
||
print(f" {el.element_navn}{simpel} ({el.rod_sti})")
|
||
if el.overliggende:
|
||
print(f" Overliggende: {el.overliggende}")
|
||
|
||
print(f"\nGenererer YAML-filer i: {output}")
|
||
|
||
from yaml_generator import (
|
||
generer_skabeloner_yaml,
|
||
generer_nøgler_yaml,
|
||
generer_udtræk_yaml,
|
||
generer_choice_udtræk_yaml,
|
||
generer_hoved_config
|
||
)
|
||
|
||
liste_navne = {el.element_navn for el in xsd.liste_elementer}
|
||
generer_skabeloner_yaml(
|
||
xsd.komplekse_typer, output, forkortelser, liste_navne, xsd.liste_elementer
|
||
)
|
||
generer_nøgler_yaml(xsd.liste_elementer, output, forkortelser)
|
||
generer_udtræk_yaml(
|
||
xsd.liste_elementer, xsd.komplekse_typer,
|
||
output, prefix, min_felter, forkortelser,
|
||
db_schema, tabel_prefix, output_type, historik
|
||
)
|
||
generer_choice_udtræk_yaml(
|
||
xsd.choice_elementer,
|
||
xsd.komplekse_typer,
|
||
xsd.liste_elementer,
|
||
output, prefix, forkortelser,
|
||
db_schema, tabel_prefix,
|
||
output_type, historik
|
||
)
|
||
|
||
generer_hoved_config(
|
||
xsd.liste_elementer, xsd_sti, output, prefix, forkortelser
|
||
)
|
||
|
||
print("\nFærdig.")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main() |