660 lines
28 KiB
Python
660 lines
28 KiB
Python
"""
|
||
yaml_generator.py
|
||
|
||
Fælles YAML-generering til brug med udpak_semistruktur.
|
||
Importeres af xsd_til_yaml.py, jsonschema_til_yaml.py og elastic_til_yaml.py.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
import os
|
||
from generators.schema_dataklasser import XsdFelt, XsdSkabelonRef, XsdKompleksType, XsdListeElement
|
||
|
||
|
||
# ============================================================
|
||
# Hjælpefunktioner
|
||
# ============================================================
|
||
|
||
def _find_fælles_prefix(liste_elementer: list) -> int:
|
||
if not liste_elementer:
|
||
return 0
|
||
# Udelad rod-elementet (første element med korteste sti)
|
||
alle_stier = [el.rod_sti.split(".") for el in liste_elementer if len(el.rod_sti.split(".")) > 1]
|
||
if not alle_stier:
|
||
return 0
|
||
korteste = min(len(s) for s in alle_stier)
|
||
fælles = 0
|
||
for i in range(korteste):
|
||
if len(set(s[i] for s in alle_stier)) == 1:
|
||
fælles += 1
|
||
else:
|
||
break
|
||
return min(fælles, korteste - 1)
|
||
|
||
|
||
def _byg_choice_grupper(liste_elementer: list) -> dict[str, dict]:
|
||
"""
|
||
Grupperer liste-elementer der deler samme rod op til choice-niveauet.
|
||
Returnerer dict: rod_sti → {
|
||
'fælles_rod': str,
|
||
'valg': [str], # fx ['Entity', 'Individual']
|
||
'element_navn': str, # fx 'Address'
|
||
'samlet_rod': str # fx 'CARF_OECD...UserID.[Entity, Individual].Address'
|
||
}
|
||
"""
|
||
from collections import defaultdict
|
||
grupper: dict[str, list] = defaultdict(list)
|
||
|
||
for el in liste_elementer:
|
||
dele = el.rod_sti.split(".")
|
||
# Nøglen er: alt undtagen næstsidste led (choice-leddet)
|
||
if len(dele) >= 2:
|
||
nøgle = ".".join(dele[:-2]) + "." + dele[-1] # fjern choice-leddet
|
||
grupper[nøgle].append(el)
|
||
|
||
resultat = {}
|
||
for nøgle, elementer in grupper.items():
|
||
if len(elementer) > 1:
|
||
valg = [el.rod_sti.split(".")[-2] for el in elementer]
|
||
fælles_rod = ".".join(elementer[0].rod_sti.split(".")[:-2])
|
||
element_navn = elementer[0].rod_sti.split(".")[-1]
|
||
samlet = f"{fælles_rod}.[{', '.join(valg)}].{element_navn}"
|
||
for el in elementer:
|
||
resultat[el.rod_sti] = {
|
||
'fælles_rod': fælles_rod,
|
||
'valg': valg,
|
||
'element_navn': element_navn,
|
||
'samlet_rod': samlet
|
||
}
|
||
return resultat
|
||
|
||
|
||
def _anvend_forkortelser(navn: str, forkortelser: dict[str, str]) -> str:
|
||
"""Anvender forkortelser case-insensitivt."""
|
||
resultat = navn
|
||
for langt, kort in forkortelser.items():
|
||
resultat = resultat.replace(langt.lower(), kort.lower())
|
||
resultat = resultat.replace(langt, kort)
|
||
return resultat
|
||
|
||
|
||
def _xsd_type_til_yaml(xsd_type: str) -> dict:
|
||
"""Konverterer XSD-type til YAML-attributter."""
|
||
t = xsd_type.lower()
|
||
if "decimal" in t:
|
||
return {"type": "decimal", "decimaler": 2}
|
||
if "integer" in t or ("int" in t and "string" not in t):
|
||
return {"type": "integer"}
|
||
if "boolean" in t:
|
||
return {"type": "boolean"}
|
||
if "datetime" in t:
|
||
return {"type": "date",
|
||
"dato_ind": '"%Y-%m-%dT%H:%M:%S"',
|
||
"dato_ud": '"SYBASE"'}
|
||
if "date" in t:
|
||
return {"type": "date",
|
||
"dato_ind": '"%Y-%m-%d"',
|
||
"dato_ud": '"%d-%m-%Y"'}
|
||
return {}
|
||
|
||
|
||
def _skriv_felt(felt: XsdFelt, indryk: str, forkortelser: dict,
|
||
liste_navne: set = set(),
|
||
fil_navne_index: dict = {}) -> list[str]:
|
||
# Tjek på felt_ref – ikke navn – da navn kan være forkortet
|
||
rod_del = felt.felt_ref.split(".")[0] if "." in felt.felt_ref else ""
|
||
er_i_liste_fil = rod_del and rod_del in liste_navne
|
||
|
||
linjer = []
|
||
navn = _anvend_forkortelser(felt.yaml_navn, forkortelser)
|
||
|
||
# if rod_del:
|
||
# print(f" DEBUG: rod_del='{rod_del}' er_i_liste_fil={er_i_liste_fil} liste_navne_sample={list(liste_navne)[:5]}")
|
||
|
||
if er_i_liste_fil:
|
||
fil_navn = fil_navne_index.get(rod_del, f"udtræk_{rod_del.lower()}.yaml")
|
||
linjer.append(f'')
|
||
linjer.append(f'{indryk}# OBS: {rod_del} har sin egen udtræk-fil: {fil_navn}')
|
||
linjer.append(f'{indryk}# - navn: {navn}')
|
||
linjer.append(f'{indryk}# felt: "{felt.felt_ref}"')
|
||
else:
|
||
linjer.append(f'')
|
||
navn_str = f'"{navn}"' if navn.startswith("#") else navn
|
||
linjer.append(f'{indryk}- navn: {navn_str}')
|
||
linjer.append(f'{indryk} felt: "{felt.felt_ref}"')
|
||
for k, v in _xsd_type_til_yaml(felt.xsd_type).items():
|
||
linjer.append(f'{indryk} {k}: {v}')
|
||
if felt.påkrævet:
|
||
linjer.append(f'{indryk} påkrævet: true')
|
||
if felt.er_liste:
|
||
linjer.append(f'{indryk} join: true')
|
||
linjer.append(f'{indryk} join_separator: ", "')
|
||
linjer.append(f'{indryk} # OBS: Kan forekomme flere gange (maxOccurs > 1)')
|
||
|
||
return linjer
|
||
|
||
def _skriv_skabelon_ref(ref: XsdSkabelonRef, indryk: str, forkortelser: dict,
|
||
liste_navne: set = set(), tomme_skabeloner: set = set(),
|
||
fil_navne_index: dict = {}) -> list[str]:
|
||
linjer = []
|
||
prefix_navn = _anvend_forkortelser(ref.prefix_navn, forkortelser)
|
||
|
||
# Tjek om prefix_felt matcher et liste-element – med eller uden punktum
|
||
rod_del = ref.prefix_felt.split(".")[0] if "." in ref.prefix_felt else ref.prefix_felt
|
||
er_i_liste_fil = rod_del and rod_del in liste_navne
|
||
|
||
# Tjek om skabelonen er tom (alle felter udkommenteret)
|
||
er_tom_skabelon = ref.skabelon_navn in tomme_skabeloner
|
||
|
||
if er_i_liste_fil or er_tom_skabelon:
|
||
linjer.append(f'')
|
||
if er_i_liste_fil:
|
||
fil_navn = fil_navne_index.get(rod_del, f"udtræk_{rod_del.lower()}.yaml")
|
||
linjer.append(f'{indryk}# OBS: {rod_del} har sin egen udtræk-fil: {fil_navn}')
|
||
else:
|
||
linjer.append(f'{indryk}# OBS: {ref.skabelon_navn} skabelonen er tom – alle felter har egne udtræk-filer')
|
||
linjer.append(f'{indryk}# - skabelon: {ref.skabelon_navn}')
|
||
linjer.append(f'{indryk}# prefix_felt: {ref.prefix_felt}')
|
||
linjer.append(f'{indryk}# prefix_navn: "{prefix_navn}"')
|
||
return linjer
|
||
|
||
if ref.er_choice:
|
||
linjer.append(f'')
|
||
linjer.append(f'{indryk}# Vælg ét alternativ (choice):')
|
||
else:
|
||
linjer.append(f'')
|
||
linjer.append(f'{indryk}- skabelon: {ref.skabelon_navn}')
|
||
linjer.append(f'{indryk} prefix_felt: {ref.prefix_felt}')
|
||
linjer.append(f'{indryk} prefix_navn: "{prefix_navn}"')
|
||
if ref.er_choice:
|
||
linjer.append(f'{indryk} hvis_findes: {ref.prefix_felt}')
|
||
if ref.er_liste:
|
||
element_basis = ref.element_navn.lower().split(".")[-1]
|
||
fil_navn_hint = fil_navne_index.get(
|
||
ref.element_navn.split(".")[-1],
|
||
f"udtræk_{element_basis}.yaml"
|
||
)
|
||
linjer.append(f'{indryk} # OBS: Kan forekomme flere gange (maxOccurs > 1).')
|
||
linjer.append(f'{indryk} # Overvej om det skal udtrækkes i en separat fil.')
|
||
linjer.append(f'{indryk} # Se evt. {fil_navn_hint}')
|
||
return linjer
|
||
|
||
def _har_aktive_felter(kt: XsdKompleksType, liste_navne: set[str]) -> bool:
|
||
"""Returnerer True hvis skabelonen har mindst ét aktivt felt
|
||
der ikke er udkommenteret fordi det har sin egen udtræk-fil."""
|
||
return any(
|
||
not (isinstance(f, XsdSkabelonRef) and
|
||
(f.prefix_felt.split(".")[0] if "." in f.prefix_felt else f.prefix_felt) in liste_navne)
|
||
and not (isinstance(f, XsdFelt) and
|
||
(f.felt_ref.split(".")[0] if "." in f.felt_ref else "") in liste_navne)
|
||
for f in kt.felter
|
||
)
|
||
|
||
# ============================================================
|
||
# Generator: skabeloner.yaml
|
||
# ============================================================
|
||
|
||
def generer_skabeloner_yaml(
|
||
komplekse_typer: dict[str, XsdKompleksType],
|
||
output_mappe: str,
|
||
forkortelser: dict[str, str] = {},
|
||
liste_navne: set[str] = set(),
|
||
liste_elementer: list = [] # ← tilføj
|
||
) -> None:
|
||
|
||
fælles_prefix_længde = _find_fælles_prefix(liste_elementer)
|
||
fil_navne_index: dict[str, str] = {}
|
||
for el in liste_elementer:
|
||
rod_dele = el.rod_sti.split(".")
|
||
unikke_dele = rod_dele[fælles_prefix_længde:] if len(rod_dele) > fælles_prefix_længde else rod_dele
|
||
fil_del = _anvend_forkortelser("_".join(unikke_dele).lower(), forkortelser)
|
||
# Behold kun første registrering per element-navn
|
||
if el.element_navn not in fil_navne_index:
|
||
fil_navne_index[el.element_navn] = f"udtræk_{fil_del}.yaml"
|
||
|
||
linjer = []
|
||
linjer.append("# =============================================================================")
|
||
linjer.append("# skabeloner.yaml")
|
||
linjer.append("#")
|
||
linjer.append("# Auto-genereret feltskabeloner fra XSD.")
|
||
linjer.append("# Brug prefix_felt og prefix_navn når skabelonen inkluderes.")
|
||
linjer.append("# =============================================================================")
|
||
linjer.append("")
|
||
linjer.append("kolonne_skabeloner:")
|
||
linjer.append("")
|
||
|
||
# Byg sæt af tomme skabeloner
|
||
tomme_skabeloner = {
|
||
kt.navn.replace("_Type", "").replace("Type", "").lower()
|
||
for kt in komplekse_typer.values()
|
||
if kt.felter and not kt.er_ekstern and not _har_aktive_felter(kt, liste_navne)
|
||
}
|
||
|
||
relevante = {n: kt for n, kt in komplekse_typer.items()
|
||
if kt.felter and not kt.er_ekstern and _har_aktive_felter(kt, liste_navne)}
|
||
|
||
for type_navn, kt in relevante.items():
|
||
skabelon_navn = type_navn.replace("_Type", "").replace("Type", "").lower()
|
||
|
||
linjer.append(f" # {type_navn}")
|
||
if not _har_aktive_felter(kt, liste_navne):
|
||
linjer.append(f" {skabelon_navn}: []")
|
||
linjer.append("")
|
||
continue
|
||
|
||
linjer.append(f" {skabelon_navn}:")
|
||
for felt in kt.felter:
|
||
if isinstance(felt, XsdSkabelonRef):
|
||
linjer.extend(_skriv_skabelon_ref(
|
||
felt, indryk=" ", forkortelser=forkortelser,
|
||
liste_navne=liste_navne, tomme_skabeloner=tomme_skabeloner,
|
||
fil_navne_index=fil_navne_index
|
||
))
|
||
elif isinstance(felt, XsdFelt):
|
||
linjer.extend(_skriv_felt(
|
||
felt, indryk=" ", forkortelser=forkortelser,
|
||
liste_navne=liste_navne, fil_navne_index=fil_navne_index
|
||
))
|
||
linjer.append("")
|
||
|
||
sti = os.path.join(output_mappe, "skabeloner.yaml")
|
||
with open(sti, "w", encoding="utf-8") as f:
|
||
f.write("\n".join(linjer))
|
||
print(f" Skrev: {sti}")
|
||
|
||
|
||
# ============================================================
|
||
# Generator: choice udtræk-filer
|
||
# ============================================================
|
||
|
||
def generer_choice_udtræk_yaml(
|
||
choice_elementer: list,
|
||
komplekse_typer: dict,
|
||
liste_elementer: list,
|
||
output_mappe: str,
|
||
prefix: str = "udtræk",
|
||
forkortelser: dict = {},
|
||
db_schema: str = "dbo",
|
||
tabel_prefix: str = "",
|
||
output_type: str = "begge",
|
||
historik: str = "t2"
|
||
) -> None:
|
||
from generators.schema_dataklasser import XsdChoiceElement, XsdSkabelonRef, XsdFelt
|
||
|
||
liste_navne = {el.element_navn for el in liste_elementer}
|
||
fælles_prefix_længde = _find_fælles_prefix(liste_elementer)
|
||
|
||
for ce in choice_elementer:
|
||
# Find den overliggende komplekse type
|
||
overliggende_type = None
|
||
rod_element_navn = ce.rod_sti.split(".")[-1]
|
||
for el in liste_elementer:
|
||
if el.element_navn == rod_element_navn and el.type_navn:
|
||
type_navn_rent = el.type_navn.split(":")[-1] if ":" in el.type_navn else el.type_navn
|
||
overliggende_type = komplekse_typer.get(type_navn_rent)
|
||
break
|
||
|
||
for alt_navn, alt_skabelon, alt_sti in ce.alternativer:
|
||
# Byg filnavn med samme prefix-logik som generer_udtræk_yaml
|
||
rod_dele = ce.rod_sti.split(".")
|
||
unikke_dele = rod_dele[fælles_prefix_længde:] if len(rod_dele) > fælles_prefix_længde else rod_dele
|
||
rod_del_str = _anvend_forkortelser("_".join(unikke_dele).lower(), forkortelser)
|
||
alt_forkortet = _anvend_forkortelser(alt_navn.lower(), forkortelser)
|
||
fil_del = f"{rod_del_str}_{alt_forkortet}"
|
||
fil_navn = f"{prefix}_{fil_del}.yaml"
|
||
|
||
hvis_finder_sti = f"{ce.element_navn}.{alt_navn}"
|
||
prefix_navn = _anvend_forkortelser(
|
||
f"{ce.element_navn.lower()}_{alt_navn.lower()}_".replace(".", "_"),
|
||
forkortelser
|
||
)
|
||
|
||
linjer = []
|
||
linjer.append("# =============================================================================")
|
||
linjer.append(f"# {fil_navn}")
|
||
linjer.append("#")
|
||
linjer.append(f"# Auto-genereret udtræk for {rod_element_navn} – {alt_navn} alternativ.")
|
||
linjer.append(f"# Rod-sti: {ce.rod_sti}")
|
||
linjer.append(f"# Kører kun hvis {hvis_finder_sti} eksisterer i XML.")
|
||
if ce.overliggende:
|
||
linjer.append("#")
|
||
linjer.append("# Udfyld nøgle-skabeloner i nøgler.yaml inden brug.")
|
||
linjer.append("# =============================================================================")
|
||
linjer.append("")
|
||
linjer.append("output_filer:")
|
||
linjer.append("")
|
||
linjer.append(f" - rod: {ce.rod_sti}")
|
||
linjer.append(f" hvis_findes: {hvis_finder_sti}")
|
||
linjer.append(f" kolonner:")
|
||
|
||
# Nøgler
|
||
if ce.overliggende:
|
||
linjer.append(f" # Nøgler fra overliggende niveauer – udfyld i nøgler.yaml")
|
||
for ov_navn in ce.overliggende:
|
||
skabelon_navn = _anvend_forkortelser(
|
||
f"{ov_navn.lower()}_nøgle", forkortelser
|
||
)
|
||
linjer.append(f" - skabelon: {skabelon_navn}")
|
||
linjer.append("")
|
||
|
||
# Choice-alternativets skabelon
|
||
linjer.append(f" # {alt_navn} felter")
|
||
linjer.append(f" - skabelon: {alt_skabelon}")
|
||
linjer.append(f" prefix_felt: {ce.element_navn}.{alt_navn}")
|
||
linjer.append(f' prefix_navn: "{prefix_navn}"')
|
||
|
||
# Øvrige felter fra den overliggende type
|
||
if overliggende_type and overliggende_type.felter:
|
||
ikke_choice_felter = [
|
||
f for f in overliggende_type.felter
|
||
if not (isinstance(f, XsdSkabelonRef) and f.er_choice)
|
||
and not (isinstance(f, XsdFelt) and f.er_choice)
|
||
]
|
||
if ikke_choice_felter:
|
||
linjer.append("")
|
||
linjer.append(f" # Øvrige felter fra {rod_element_navn}")
|
||
for felt in ikke_choice_felter:
|
||
if isinstance(felt, XsdSkabelonRef):
|
||
linjer.extend(_skriv_skabelon_ref(
|
||
felt, " ", forkortelser, liste_navne
|
||
))
|
||
elif isinstance(felt, XsdFelt):
|
||
linjer.extend(_skriv_felt(
|
||
felt, " ", forkortelser, liste_navne
|
||
))
|
||
|
||
linjer.append("")
|
||
linjer.append(f" outputs:")
|
||
|
||
if output_type in ("fil", "begge"):
|
||
linjer.append(f" - fil_navn: \"{fil_del}_{{yyyy}}{{mm}}{{dd}}.txt\"")
|
||
linjer.append(f" overskrifter: true")
|
||
linjer.append("")
|
||
|
||
if output_type in ("tabel", "begge"):
|
||
tabel_navn = f"{tabel_prefix}{fil_del}"
|
||
linjer.append(f" - tabel:")
|
||
linjer.append(f" staging: {db_schema}.{tabel_navn}_tmp")
|
||
linjer.append(f" blivende: {db_schema}.{tabel_navn}")
|
||
linjer.append(f" historik: {historik}")
|
||
linjer.append(f" # TODO: Angiv forretningsnøgler")
|
||
linjer.append(f" forretnings_nøgler: [__NØGLE__]")
|
||
linjer.append(f" tekniske_nøgler: [løbenummer]")
|
||
linjer.append(f" ekstra_kolonner:")
|
||
linjer.append(f" - navn: løbenummer")
|
||
linjer.append(f' ddl_type: "int identity"')
|
||
linjer.append(f" placering: start")
|
||
linjer.append("")
|
||
|
||
sti = os.path.join(output_mappe, fil_navn)
|
||
with open(sti, "w", encoding="utf-8") as f:
|
||
f.write("\n".join(linjer))
|
||
print(f" Skrev: {sti}")
|
||
|
||
# ============================================================
|
||
# Generator: nøgler.yaml
|
||
# ============================================================
|
||
|
||
def generer_nøgler_yaml(
|
||
liste_elementer: list[XsdListeElement],
|
||
output_mappe: str,
|
||
forkortelser: dict[str, str] = {}
|
||
) -> None:
|
||
# Find unikke overliggende niveauer
|
||
overliggende: dict[str, str] = {}
|
||
for el in liste_elementer:
|
||
rod_dele = el.rod_sti.split(".")
|
||
for ov_navn in el.overliggende:
|
||
if ov_navn not in overliggende:
|
||
try:
|
||
idx = rod_dele.index(ov_navn)
|
||
overliggende[ov_navn] = ".".join(rod_dele[:idx + 1])
|
||
except ValueError:
|
||
overliggende[ov_navn] = f"__{ov_navn.upper()}__"
|
||
|
||
if not overliggende:
|
||
return
|
||
|
||
linjer = []
|
||
linjer.append("# =============================================================================")
|
||
linjer.append("# nøgler.yaml")
|
||
linjer.append("#")
|
||
linjer.append("# Nøgle-skabeloner der binder udtræk-filer til overliggende niveauer.")
|
||
linjer.append("# UDFYLD: Erstat __FELT__ med den korrekte forretningsnøgle.")
|
||
linjer.append("# =============================================================================")
|
||
linjer.append("")
|
||
linjer.append("kolonne_skabeloner:")
|
||
linjer.append("")
|
||
|
||
for ov_navn, ov_rod_sti in overliggende.items():
|
||
skabelon_navn = _anvend_forkortelser(f"{ov_navn.lower()}_nøgle", forkortelser)
|
||
linjer.append(f" # Nøgle fra {ov_navn}-niveau")
|
||
linjer.append(f" # TODO: Angiv den korrekte forretningsnøgle for {ov_navn}")
|
||
linjer.append(f" {skabelon_navn}:")
|
||
linjer.append(f" - navn: __FELT__")
|
||
linjer.append(f" felt: \"__FELT__\" # fx \"@id\" eller \"nr\"")
|
||
linjer.append(f" rod: {ov_rod_sti}")
|
||
linjer.append("")
|
||
|
||
sti = os.path.join(output_mappe, "nøgler.yaml")
|
||
with open(sti, "w", encoding="utf-8") as f:
|
||
f.write("\n".join(linjer))
|
||
print(f" Skrev: {sti}")
|
||
|
||
|
||
def generer_udtræk_yaml(
|
||
liste_elementer: list[XsdListeElement],
|
||
komplekse_typer: dict[str, XsdKompleksType],
|
||
output_mappe: str,
|
||
prefix: str = "udtræk",
|
||
min_felter: int = 1,
|
||
forkortelser: dict[str, str] = {},
|
||
db_schema: str = "dbo",
|
||
tabel_prefix: str = "",
|
||
output_type: str = "begge",
|
||
historik: str = "t2"
|
||
) -> None:
|
||
|
||
# Beregn fælles prefix på tværs af alle rod-stier
|
||
fælles_prefix_længde = _find_fælles_prefix(liste_elementer)
|
||
|
||
fil_navne_index: dict[str, str] = {}
|
||
for el in liste_elementer:
|
||
rod_dele = el.rod_sti.split(".")
|
||
unikke_dele = rod_dele[fælles_prefix_længde:] if len(rod_dele) > fælles_prefix_længde else rod_dele
|
||
fil_del = _anvend_forkortelser("_".join(unikke_dele).lower(), forkortelser)
|
||
if el.element_navn not in fil_navne_index:
|
||
fil_navne_index[el.element_navn] = f"udtræk_{fil_del}.yaml"
|
||
|
||
# Byg choice-grupper til kommentar-generering (ikke filnavne)
|
||
choice_grupper = _byg_choice_grupper(liste_elementer)
|
||
|
||
# Byg sæt af liste-element navne til udkommentering
|
||
liste_navne = {el.element_navn for el in liste_elementer}
|
||
|
||
for el in liste_elementer:
|
||
|
||
# Byg unikt filnavn fra rod-stien minus fælles prefix
|
||
rod_dele = el.rod_sti.split(".")
|
||
unikke_dele = rod_dele[fælles_prefix_længde:] if len(rod_dele) > fælles_prefix_længde else rod_dele
|
||
fil_del = _anvend_forkortelser(
|
||
"_".join(unikke_dele).lower(), forkortelser
|
||
)
|
||
fil_navn = f"{prefix}_{fil_del}.yaml"
|
||
|
||
gruppe = choice_grupper.get(el.rod_sti)
|
||
|
||
linjer = []
|
||
linjer.append("# =============================================================================")
|
||
linjer.append(f"# {fil_navn}")
|
||
linjer.append("#")
|
||
linjer.append(f"# Auto-genereret udtræk for {el.element_navn}.")
|
||
linjer.append(f"# Rod-sti: {el.rod_sti}")
|
||
if el.er_simpel:
|
||
linjer.append("#")
|
||
linjer.append(f"# OBS: Dette element er simpelt ({el.element_navn} har få felter).")
|
||
linjer.append(f"# Det er foldet ind som join-kolonne i skabelon: {el.join_i_skabelon}")
|
||
linjer.append(f"# Denne fil er udkommenteret i config – fjern udkommentering for fuldt udtræk.")
|
||
if el.overliggende:
|
||
linjer.append("#")
|
||
linjer.append("# Udfyld nøgle-skabeloner i nøgler.yaml inden brug.")
|
||
if gruppe:
|
||
linjer.append("#")
|
||
linjer.append("# OBS: Dette element forekommer i flere choice-grene:")
|
||
for valg in gruppe['valg']:
|
||
sti = f"{gruppe['fælles_rod']}.{valg}.{gruppe['element_navn']}"
|
||
linjer.append(f"# - {sti}")
|
||
linjer.append("# Disse kan samles i én fil ved at ændre rod til en rod med varianter:")
|
||
linjer.append(f"# rod: {gruppe['samlet_rod']}")
|
||
linjer.append("# Tilføj evt. en kolonne til at skelne grenene:")
|
||
linjer.append("# - navn: bruger_type")
|
||
linjer.append("# type: rod_variant")
|
||
linjer.append("# =============================================================================")
|
||
linjer.append("")
|
||
linjer.append("output_filer:")
|
||
linjer.append("")
|
||
linjer.append(f" - rod: {el.rod_sti}")
|
||
linjer.append(f" kolonner:")
|
||
|
||
# Nøgler
|
||
if el.overliggende:
|
||
linjer.append(f" # Nøgler fra overliggende niveauer – udfyld i nøgler.yaml")
|
||
for ov_navn in el.overliggende:
|
||
skabelon_navn = _anvend_forkortelser(
|
||
f"{ov_navn.lower()}_nøgle", forkortelser
|
||
)
|
||
linjer.append(f" - skabelon: {skabelon_navn}")
|
||
linjer.append("")
|
||
|
||
# Felter fra elementets type eller inline felter
|
||
type_navn_rent = _strip_prefix(el.type_navn) if el.type_navn else ""
|
||
kt = komplekse_typer.get(type_navn_rent)
|
||
|
||
if kt and kt.felter and not kt.er_ekstern:
|
||
skabelon_navn = type_navn_rent.replace("_Type", "").replace("Type", "").lower()
|
||
linjer.append(f" # Felter fra {el.element_navn} – se skabeloner.yaml")
|
||
linjer.append(f" - skabelon: {skabelon_navn}")
|
||
elif el.felter:
|
||
linjer.append(f" # Felter fra {el.element_navn}")
|
||
for felt in el.felter:
|
||
if isinstance(felt, XsdSkabelonRef):
|
||
linjer.extend(_skriv_skabelon_ref(
|
||
felt, " ", forkortelser, liste_navne,
|
||
fil_navne_index=fil_navne_index
|
||
))
|
||
elif isinstance(felt, XsdFelt):
|
||
linjer.extend(_skriv_felt(
|
||
felt, " ", forkortelser, liste_navne # ← tilføj liste_navne
|
||
))
|
||
elif el.er_simpel:
|
||
linjer.append(f" # Feltets egen værdi")
|
||
linjer.append(f" - navn: {el.element_navn}")
|
||
linjer.append(f" felt: \".\"")
|
||
|
||
linjer.append("")
|
||
linjer.append(f" outputs:")
|
||
|
||
if output_type in ("fil", "begge"):
|
||
linjer.append(f" - fil_navn: \"{fil_del}_{{yyyy}}{{mm}}{{dd}}.txt\"")
|
||
linjer.append(f" overskrifter: true")
|
||
linjer.append("")
|
||
|
||
if output_type in ("tabel", "begge"):
|
||
tabel_navn = f"{tabel_prefix}{fil_del}"
|
||
linjer.append(f" - tabel:")
|
||
linjer.append(f" staging: {db_schema}.{tabel_navn}_tmp")
|
||
linjer.append(f" blivende: {db_schema}.{tabel_navn}")
|
||
linjer.append(f" historik: {historik}")
|
||
linjer.append(f" # TODO: Angiv forretningsnøgler")
|
||
linjer.append(f" forretnings_nøgler: [__NØGLE__]")
|
||
linjer.append(f" tekniske_nøgler: [løbenummer]")
|
||
linjer.append(f" ekstra_kolonner:")
|
||
linjer.append(f" - navn: løbenummer")
|
||
linjer.append(f' ddl_type: "int identity"')
|
||
linjer.append(f" placering: start")
|
||
linjer.append("")
|
||
linjer.append("")
|
||
|
||
sti = os.path.join(output_mappe, fil_navn)
|
||
with open(sti, "w", encoding="utf-8") as f:
|
||
f.write("\n".join(linjer))
|
||
print(f" Skrev: {sti}")
|
||
|
||
# ============================================================
|
||
# Generator: config_xxx.yaml
|
||
# ============================================================
|
||
|
||
def generer_hoved_config(
|
||
liste_elementer: list[XsdListeElement],
|
||
xsd_sti: str,
|
||
output_mappe: str,
|
||
prefix: str = "udtræk",
|
||
forkortelser: dict[str, str] = {}
|
||
) -> None:
|
||
xsd_basis = os.path.splitext(os.path.basename(xsd_sti))[0]
|
||
|
||
# Beregn fælles prefix – samme logik som generer_udtræk_yaml
|
||
fælles_prefix_længde = _find_fælles_prefix(liste_elementer)
|
||
|
||
linjer = []
|
||
linjer.append("# =============================================================================")
|
||
linjer.append(f"# config_{xsd_basis}.yaml")
|
||
linjer.append("#")
|
||
linjer.append("# Auto-genereret hoved-config.")
|
||
linjer.append("# Tilpas config-sektionen med korrekte stier og indstillinger.")
|
||
linjer.append("# =============================================================================")
|
||
linjer.append("")
|
||
linjer.append("include:")
|
||
linjer.append(" - skabeloner.yaml")
|
||
linjer.append(" - nøgler.yaml")
|
||
linjer.append("")
|
||
|
||
normale = []
|
||
simple = []
|
||
|
||
for el in liste_elementer:
|
||
rod_dele = el.rod_sti.split(".")
|
||
unikke_dele = rod_dele[fælles_prefix_længde:] if len(rod_dele) > fælles_prefix_længde else rod_dele
|
||
fil_del = _anvend_forkortelser(
|
||
"_".join(unikke_dele).lower(), forkortelser
|
||
)
|
||
fil = f"{prefix}_{fil_del}.yaml"
|
||
if el.er_simpel:
|
||
simple.append((fil, el))
|
||
else:
|
||
normale.append((fil, el))
|
||
|
||
for fil, _ in normale:
|
||
linjer.append(f" - {fil}")
|
||
|
||
if simple:
|
||
linjer.append("")
|
||
linjer.append(" # Simple lister – foldet ind som join-kolonner i skabelonerne:")
|
||
linjer.append(" # Fjern udkommentering for fuldt udtræk i stedet for join.")
|
||
for fil, el in simple:
|
||
linjer.append(f" # - {fil} (join i skabelon: {el.join_i_skabelon})")
|
||
|
||
linjer.append("")
|
||
linjer.append("config:")
|
||
linjer.append(f" input_fil: {xsd_basis}.xml")
|
||
linjer.append(" output_path: __OUTPUT_PATH__")
|
||
linjer.append(" logfil: log_{yyyy}{mm}{dd}.txt")
|
||
linjer.append(" log_niveau: info")
|
||
linjer.append(" log_output: begge")
|
||
linjer.append(" encoding: utf-8")
|
||
linjer.append(' separator: "\\t"')
|
||
linjer.append(" skrivetilstand: w")
|
||
linjer.append(' dato_ind: "%Y-%m-%d"')
|
||
linjer.append(' dato_ud: "%d-%m-%Y"')
|
||
|
||
sti = os.path.join(output_mappe, f"config_{xsd_basis}.yaml")
|
||
with open(sti, "w", encoding="utf-8") as f:
|
||
f.write("\n".join(linjer))
|
||
print(f" Skrev: {sti}")
|
||
|
||
def _strip_prefix(type_navn: str) -> str:
|
||
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 |