diff --git a/dokumente/management/commands/export_xml.py b/dokumente/management/commands/export_xml.py index fe0bb28..e5412ed 100644 --- a/dokumente/management/commands/export_xml.py +++ b/dokumente/management/commands/export_xml.py @@ -1,40 +1,7 @@ from django.core.management.base import BaseCommand import xml.etree.ElementTree as ET -from datetime import datetime -from dokumente.models import Dokument, Vorgabe, VorgabeKurztext, VorgabeLangtext, Checklistenfrage - - -def _parse_markdown_table(markdown_content): - """ - Parse markdown table content and return XML element with
structure - """ - lines = [line.strip() for line in markdown_content.strip().split('\n') if line.strip()] - if not lines: - return None - - # Create table element - table = ET.Element('table') - - # Parse first row as header - header_row = [cell.strip() for cell in lines[0].split('|') if cell.strip()] - header = ET.SubElement(table, 'header') - for cell in header_row: - column = ET.SubElement(header, 'column') - column.text = cell - - # Parse remaining rows (skip separator row if it exists) - for line in lines[2:] if len(lines) > 1 and all(c in '-| ' for c in lines[1]) else lines[1:]: - # Check if this is a separator row - if all(c in '-| ' for c in line): - continue - - row = ET.SubElement(table, 'row') - row_cells = [cell.strip() for cell in line.split('|') if cell.strip()] - for cell in row_cells: - column = ET.SubElement(row, 'column') - column.text = cell - - return table +from dokumente.models import Dokument +from dokumente.utils import build_dokument_xml_element, prettify_xml class Command(BaseCommand): @@ -49,7 +16,7 @@ class Command(BaseCommand): def handle(self, *args, **options): dokumente = Dokument.objects.filter(aktiv=True).prefetch_related( - 'autoren', 'pruefende', 'vorgaben__thema', + 'autoren', 'pruefende', 'vorgaben__thema', 'vorgaben__referenzen', 'vorgaben__stichworte', 'vorgaben__checklistenfragen', 'vorgaben__vorgabekurztext_set', 'vorgaben__vorgabelangtext_set', 'geltungsbereich_set', @@ -59,147 +26,14 @@ class Command(BaseCommand): root = ET.Element('Vorgabendokumente') for dokument in dokumente: - doc_element = ET.SubElement(root, 'Vorgabendokument') - - ET.SubElement(doc_element, 'Typ').text = dokument.dokumententyp.name if dokument.dokumententyp else "" - ET.SubElement(doc_element, 'Nummer').text = dokument.nummer - ET.SubElement(doc_element, 'Name').text = dokument.name - - autoren_element = ET.SubElement(doc_element, 'Autoren') - for autor in dokument.autoren.all(): - ET.SubElement(autoren_element, 'Autor').text = autor.name - - pruefende_element = ET.SubElement(doc_element, 'Pruefende') - for pruefender in dokument.pruefende.all(): - ET.SubElement(pruefende_element, 'Pruefender').text = pruefender.name - - gueltigkeit_element = ET.SubElement(doc_element, 'Gueltigkeit') - ET.SubElement(gueltigkeit_element, 'Von').text = dokument.gueltigkeit_von.strftime("%Y-%m-%d") if dokument.gueltigkeit_von else "" - ET.SubElement(gueltigkeit_element, 'Bis').text = dokument.gueltigkeit_bis.strftime("%Y-%m-%d") if dokument.gueltigkeit_bis else None - - ET.SubElement(doc_element, 'SignaturCSO').text = dokument.signatur_cso - - geltungsbereich_sections = dokument.geltungsbereich_set.all().order_by('order') - if geltungsbereich_sections: - geltungsbereich_element = ET.SubElement(doc_element, 'Geltungsbereich') - for gb in geltungsbereich_sections: - section_type = gb.abschnitttyp.abschnitttyp if gb.abschnitttyp else "text" - if section_type in ('tabelle', 'table'): - table = _parse_markdown_table(gb.inhalt) - if table is not None: - abschnitt_element = ET.SubElement(geltungsbereich_element, 'Abschnitt') - abschnitt_element.set('typ', section_type) - abschnitt_element.append(table) - else: - abschnitt_element = ET.SubElement(geltungsbereich_element, 'Abschnitt') - abschnitt_element.set('typ', section_type) - abschnitt_element.text = gb.inhalt - - einleitung_sections = dokument.einleitung_set.all().order_by('order') - if einleitung_sections: - einleitung_element = ET.SubElement(doc_element, 'Einleitung') - for ei in einleitung_sections: - section_type = ei.abschnitttyp.abschnitttyp if ei.abschnitttyp else "text" - if section_type in ('tabelle', 'table'): - table = _parse_markdown_table(ei.inhalt) - if table is not None: - abschnitt_element = ET.SubElement(einleitung_element, 'Abschnitt') - abschnitt_element.set('typ', section_type) - abschnitt_element.append(table) - else: - abschnitt_element = ET.SubElement(einleitung_element, 'Abschnitt') - abschnitt_element.set('typ', section_type) - abschnitt_element.text = ei.inhalt - - ET.SubElement(doc_element, 'Ziel').text = "" - ET.SubElement(doc_element, 'Grundlagen').text = "" - - changelog_element = ET.SubElement(doc_element, 'Changelog') - for cl in dokument.changelog.all().order_by('-datum'): - entry = ET.SubElement(changelog_element, 'Eintrag') - ET.SubElement(entry, 'Datum').text = cl.datum.strftime("%Y-%m-%d") - autoren = ET.SubElement(entry, 'Autoren') - for autor in cl.autoren.all(): - ET.SubElement(autoren, 'Autor').text = autor.name - ET.SubElement(entry, 'Aenderung').text = cl.aenderung - - anhaenge_element = ET.SubElement(doc_element, 'Anhaenge') - ET.SubElement(anhaenge_element, 'Anhang').text = dokument.anhaenge - - ET.SubElement(doc_element, 'Verantwortlich').text = "Information Security Management BIT" - ET.SubElement(doc_element, 'Klassifizierung').text = "" - - glossar_element = ET.SubElement(doc_element, 'Glossar') - - vorgaben_element = ET.SubElement(doc_element, 'Vorgaben') - - for vorgabe in dokument.vorgaben.all().order_by('order'): - vorgabe_el = ET.SubElement(vorgaben_element, 'Vorgabe') - - ET.SubElement(vorgabe_el, 'Nummer').text = str(vorgabe.nummer) - ET.SubElement(vorgabe_el, 'Titel').text = vorgabe.titel - ET.SubElement(vorgabe_el, 'Thema').text = vorgabe.thema.name if vorgabe.thema else "" - - kurztext_sections = vorgabe.vorgabekurztext_set.all().order_by('order') - if kurztext_sections: - kurztext_element = ET.SubElement(vorgabe_el, 'Kurztext') - for kt in kurztext_sections: - section_type = kt.abschnitttyp.abschnitttyp if kt.abschnitttyp else "text" - if section_type in ('tabelle', 'table'): - table = _parse_markdown_table(kt.inhalt) - if table is not None: - abschnitt = ET.SubElement(kurztext_element, 'Abschnitt') - abschnitt.set('typ', section_type) - abschnitt.append(table) - else: - abschnitt = ET.SubElement(kurztext_element, 'Abschnitt') - abschnitt.set('typ', section_type) - abschnitt.text = kt.inhalt - - langtext_sections = vorgabe.vorgabelangtext_set.all().order_by('order') - if langtext_sections: - langtext_element = ET.SubElement(vorgabe_el, 'Langtext') - for lt in langtext_sections: - section_type = lt.abschnitttyp.abschnitttyp if lt.abschnitttyp else "text" - if section_type in ('tabelle', 'table'): - table = _parse_markdown_table(lt.inhalt) - if table is not None: - abschnitt = ET.SubElement(langtext_element, 'Abschnitt') - abschnitt.set('typ', section_type) - abschnitt.append(table) - else: - abschnitt = ET.SubElement(langtext_element, 'Abschnitt') - abschnitt.set('typ', section_type) - abschnitt.text = lt.inhalt - - referenz_element = ET.SubElement(vorgabe_el, 'Referenzen') - for ref in vorgabe.referenzen.all(): - ref_text = f"{ref.name_nummer}: {ref.name_text}" if ref.name_text else ref.name_nummer - ET.SubElement(referenz_element, 'Referenz').text = ref_text - - vorgabe_gueltigkeit = ET.SubElement(vorgabe_el, 'Gueltigkeit') - ET.SubElement(vorgabe_gueltigkeit, 'Von').text = vorgabe.gueltigkeit_von.strftime("%Y-%m-%d") if vorgabe.gueltigkeit_von else "" - ET.SubElement(vorgabe_gueltigkeit, 'Bis').text = vorgabe.gueltigkeit_bis.strftime("%Y-%m-%d") if vorgabe.gueltigkeit_bis else None - - checklistenfragen_element = ET.SubElement(vorgabe_el, 'Checklistenfragen') - for cf in vorgabe.checklistenfragen.all(): - ET.SubElement(checklistenfragen_element, 'Frage').text = cf.frage - - stichworte_element = ET.SubElement(vorgabe_el, 'Stichworte') - for stw in vorgabe.stichworte.all(): - ET.SubElement(stichworte_element, 'Stichwort').text = stw.stichwort + build_dokument_xml_element(dokument, root) xml_str = ET.tostring(root, encoding='unicode', method='xml') - xml_output = self._prettify_xml(xml_str) - + xml_output = prettify_xml(xml_str) + if options['output']: with open(options['output'], 'w', encoding='utf-8') as f: f.write(xml_output) self.stdout.write(self.style.SUCCESS(f'XML exported to {options["output"]}')) else: self.stdout.write(xml_output) - - def _prettify_xml(self, xml_string): - import xml.dom.minidom - dom = xml.dom.minidom.parseString(xml_string) - return dom.toprettyxml(indent=" ", encoding="UTF-8").decode('utf-8') diff --git a/dokumente/utils.py b/dokumente/utils.py index a0c6930..22952d8 100644 --- a/dokumente/utils.py +++ b/dokumente/utils.py @@ -1,7 +1,9 @@ """ -Utility functions for Vorgaben sanity checking +Utility functions for Vorgaben sanity checking and XML export """ import datetime +import xml.etree.ElementTree as ET +import xml.dom.minidom from django.db.models import Count from itertools import combinations from dokumente.models import Vorgabe @@ -119,5 +121,192 @@ def format_conflict_report(conflicts, verbose=False): lines.append(f" Overlap: {overlap_start} to {overlap_end}") else: lines.append(f" Overlap starts: {overlap_start} (no end)") - - return "\n".join(lines) \ No newline at end of file + + return "\n".join(lines) + + +# XML Export utilities + +def parse_markdown_table(markdown_content): + """ + Parse markdown table content and return XML element with
structure + """ + lines = [line.strip() for line in markdown_content.strip().split('\n') if line.strip()] + if not lines: + return None + + # Create table element + table = ET.Element('table') + + # Parse first row as header + header_row = [cell.strip() for cell in lines[0].split('|') if cell.strip()] + header = ET.SubElement(table, 'header') + for cell in header_row: + column = ET.SubElement(header, 'column') + column.text = cell + + # Parse remaining rows (skip separator row if it exists) + for line in lines[2:] if len(lines) > 1 and all(c in '-| ' for c in lines[1]) else lines[1:]: + # Check if this is a separator row + if all(c in '-| ' for c in line): + continue + + row = ET.SubElement(table, 'row') + row_cells = [cell.strip() for cell in line.split('|') if cell.strip()] + for cell in row_cells: + column = ET.SubElement(row, 'column') + column.text = cell + + return table + + +def prettify_xml(xml_string): + """ + Prettify XML string with proper indentation + """ + dom = xml.dom.minidom.parseString(xml_string) + return dom.toprettyxml(indent=" ", encoding="UTF-8").decode('utf-8') + + +def build_dokument_xml_element(dokument, parent_element): + """ + Build XML element for a single Dokument and append it to parent_element. + + Args: + dokument: Dokument instance (should be prefetched with related data) + parent_element: Parent XML element to append to + + Returns: + The created document element + """ + doc_element = ET.SubElement(parent_element, 'Vorgabendokument') + + ET.SubElement(doc_element, 'Typ').text = dokument.dokumententyp.name if dokument.dokumententyp else "" + ET.SubElement(doc_element, 'Nummer').text = dokument.nummer + ET.SubElement(doc_element, 'Name').text = dokument.name + + autoren_element = ET.SubElement(doc_element, 'Autoren') + for autor in dokument.autoren.all(): + ET.SubElement(autoren_element, 'Autor').text = autor.name + + pruefende_element = ET.SubElement(doc_element, 'Pruefende') + for pruefender in dokument.pruefende.all(): + ET.SubElement(pruefende_element, 'Pruefender').text = pruefender.name + + gueltigkeit_element = ET.SubElement(doc_element, 'Gueltigkeit') + ET.SubElement(gueltigkeit_element, 'Von').text = dokument.gueltigkeit_von.strftime("%Y-%m-%d") if dokument.gueltigkeit_von else "" + ET.SubElement(gueltigkeit_element, 'Bis').text = dokument.gueltigkeit_bis.strftime("%Y-%m-%d") if dokument.gueltigkeit_bis else None + + ET.SubElement(doc_element, 'SignaturCSO').text = dokument.signatur_cso + + geltungsbereich_sections = dokument.geltungsbereich_set.all().order_by('order') + if geltungsbereich_sections: + geltungsbereich_element = ET.SubElement(doc_element, 'Geltungsbereich') + for gb in geltungsbereich_sections: + section_type = gb.abschnitttyp.abschnitttyp if gb.abschnitttyp else "text" + if section_type in ('tabelle', 'table'): + table = parse_markdown_table(gb.inhalt) + if table is not None: + abschnitt_element = ET.SubElement(geltungsbereich_element, 'Abschnitt') + abschnitt_element.set('typ', section_type) + abschnitt_element.append(table) + else: + abschnitt_element = ET.SubElement(geltungsbereich_element, 'Abschnitt') + abschnitt_element.set('typ', section_type) + abschnitt_element.text = gb.inhalt + + einleitung_sections = dokument.einleitung_set.all().order_by('order') + if einleitung_sections: + einleitung_element = ET.SubElement(doc_element, 'Einleitung') + for ei in einleitung_sections: + section_type = ei.abschnitttyp.abschnitttyp if ei.abschnitttyp else "text" + if section_type in ('tabelle', 'table'): + table = parse_markdown_table(ei.inhalt) + if table is not None: + abschnitt_element = ET.SubElement(einleitung_element, 'Abschnitt') + abschnitt_element.set('typ', section_type) + abschnitt_element.append(table) + else: + abschnitt_element = ET.SubElement(einleitung_element, 'Abschnitt') + abschnitt_element.set('typ', section_type) + abschnitt_element.text = ei.inhalt + + ET.SubElement(doc_element, 'Ziel').text = "" + ET.SubElement(doc_element, 'Grundlagen').text = "" + + changelog_element = ET.SubElement(doc_element, 'Changelog') + for cl in dokument.changelog.all().order_by('-datum'): + entry = ET.SubElement(changelog_element, 'Eintrag') + ET.SubElement(entry, 'Datum').text = cl.datum.strftime("%Y-%m-%d") + autoren = ET.SubElement(entry, 'Autoren') + for autor in cl.autoren.all(): + ET.SubElement(autoren, 'Autor').text = autor.name + ET.SubElement(entry, 'Aenderung').text = cl.aenderung + + anhaenge_element = ET.SubElement(doc_element, 'Anhaenge') + ET.SubElement(anhaenge_element, 'Anhang').text = dokument.anhaenge + + ET.SubElement(doc_element, 'Verantwortlich').text = "Information Security Management BIT" + ET.SubElement(doc_element, 'Klassifizierung').text = "" + + glossar_element = ET.SubElement(doc_element, 'Glossar') + + vorgaben_element = ET.SubElement(doc_element, 'Vorgaben') + + for vorgabe in dokument.vorgaben.all().order_by('order'): + vorgabe_el = ET.SubElement(vorgaben_element, 'Vorgabe') + + ET.SubElement(vorgabe_el, 'Nummer').text = str(vorgabe.nummer) + ET.SubElement(vorgabe_el, 'Titel').text = vorgabe.titel + ET.SubElement(vorgabe_el, 'Thema').text = vorgabe.thema.name if vorgabe.thema else "" + + kurztext_sections = vorgabe.vorgabekurztext_set.all().order_by('order') + if kurztext_sections: + kurztext_element = ET.SubElement(vorgabe_el, 'Kurztext') + for kt in kurztext_sections: + section_type = kt.abschnitttyp.abschnitttyp if kt.abschnitttyp else "text" + if section_type in ('tabelle', 'table'): + table = parse_markdown_table(kt.inhalt) + if table is not None: + abschnitt = ET.SubElement(kurztext_element, 'Abschnitt') + abschnitt.set('typ', section_type) + abschnitt.append(table) + else: + abschnitt = ET.SubElement(kurztext_element, 'Abschnitt') + abschnitt.set('typ', section_type) + abschnitt.text = kt.inhalt + + langtext_sections = vorgabe.vorgabelangtext_set.all().order_by('order') + if langtext_sections: + langtext_element = ET.SubElement(vorgabe_el, 'Langtext') + for lt in langtext_sections: + section_type = lt.abschnitttyp.abschnitttyp if lt.abschnitttyp else "text" + if section_type in ('tabelle', 'table'): + table = parse_markdown_table(lt.inhalt) + if table is not None: + abschnitt = ET.SubElement(langtext_element, 'Abschnitt') + abschnitt.set('typ', section_type) + abschnitt.append(table) + else: + abschnitt = ET.SubElement(langtext_element, 'Abschnitt') + abschnitt.set('typ', section_type) + abschnitt.text = lt.inhalt + + referenz_element = ET.SubElement(vorgabe_el, 'Referenzen') + for ref in vorgabe.referenzen.all(): + ref_text = f"{ref.name_nummer}: {ref.name_text}" if ref.name_text else ref.name_nummer + ET.SubElement(referenz_element, 'Referenz').text = ref_text + + vorgabe_gueltigkeit = ET.SubElement(vorgabe_el, 'Gueltigkeit') + ET.SubElement(vorgabe_gueltigkeit, 'Von').text = vorgabe.gueltigkeit_von.strftime("%Y-%m-%d") if vorgabe.gueltigkeit_von else "" + ET.SubElement(vorgabe_gueltigkeit, 'Bis').text = vorgabe.gueltigkeit_bis.strftime("%Y-%m-%d") if vorgabe.gueltigkeit_bis else None + + checklistenfragen_element = ET.SubElement(vorgabe_el, 'Checklistenfragen') + for cf in vorgabe.checklistenfragen.all(): + ET.SubElement(checklistenfragen_element, 'Frage').text = cf.frage + + stichworte_element = ET.SubElement(vorgabe_el, 'Stichworte') + for stw in vorgabe.stichworte.all(): + ET.SubElement(stichworte_element, 'Stichwort').text = stw.stichwort + + return doc_element \ No newline at end of file diff --git a/dokumente/views.py b/dokumente/views.py index 4455ba4..08ed98e 100644 --- a/dokumente/views.py +++ b/dokumente/views.py @@ -9,6 +9,7 @@ from django.utils.safestring import SafeString import json import xml.etree.ElementTree as ET from .models import Dokument, Vorgabe, VorgabeKurztext, VorgabeLangtext, Checklistenfrage, VorgabeComment +from .utils import build_dokument_xml_element, prettify_xml from abschnitte.utils import render_textabschnitte from datetime import date @@ -17,39 +18,6 @@ import parsedatetime calendar=parsedatetime.Calendar() -def _parse_markdown_table(markdown_content): - """ - Parse markdown table content and return XML element with
structure - """ - lines = [line.strip() for line in markdown_content.strip().split('\n') if line.strip()] - if not lines: - return None - - # Create table element - table = ET.Element('table') - - # Parse first row as header - header_row = [cell.strip() for cell in lines[0].split('|') if cell.strip()] - header = ET.SubElement(table, 'header') - for cell in header_row: - column = ET.SubElement(header, 'column') - column.text = cell - - # Parse remaining rows (skip separator row if it exists) - for line in lines[2:] if len(lines) > 1 and all(c in '-| ' for c in lines[1]) else lines[1:]: - # Check if this is a separator row - if all(c in '-| ' for c in line): - continue - - row = ET.SubElement(table, 'row') - row_cells = [cell.strip() for cell in line.split('|') if cell.strip()] - for cell in row_cells: - column = ET.SubElement(row, 'column') - column.text = cell - - return table - - def standard_list(request): dokumente = Dokument.objects.all() return render(request, 'standards/standard_list.html', @@ -295,7 +263,7 @@ def standard_xml(request, nummer): # Get the document with all related data dokument = get_object_or_404( Dokument.objects.prefetch_related( - 'autoren', 'pruefende', 'vorgaben__thema', + 'autoren', 'pruefende', 'vorgaben__thema', 'vorgaben__referenzen', 'vorgaben__stichworte', 'vorgaben__checklistenfragen', 'vorgaben__vorgabekurztext_set', 'vorgaben__vorgabelangtext_set', 'geltungsbereich_set', @@ -304,150 +272,21 @@ def standard_xml(request, nummer): nummer=nummer ) - root = ET.Element('Vorgabendokument') - - ET.SubElement(root, 'Typ').text = dokument.dokumententyp.name if dokument.dokumententyp else "" - ET.SubElement(root, 'Nummer').text = dokument.nummer - ET.SubElement(root, 'Name').text = dokument.name - - autoren_element = ET.SubElement(root, 'Autoren') - for autor in dokument.autoren.all(): - ET.SubElement(autoren_element, 'Autor').text = autor.name - - pruefende_element = ET.SubElement(root, 'Pruefende') - for pruefender in dokument.pruefende.all(): - ET.SubElement(pruefende_element, 'Pruefender').text = pruefender.name - - gueltigkeit_element = ET.SubElement(root, 'Gueltigkeit') - ET.SubElement(gueltigkeit_element, 'Von').text = dokument.gueltigkeit_von.strftime("%Y-%m-%d") if dokument.gueltigkeit_von else "" - ET.SubElement(gueltigkeit_element, 'Bis').text = dokument.gueltigkeit_bis.strftime("%Y-%m-%d") if dokument.gueltigkeit_bis else None - - ET.SubElement(root, 'SignaturCSO').text = dokument.signatur_cso - - geltungsbereich_sections = dokument.geltungsbereich_set.all().order_by('order') - if geltungsbereich_sections: - geltungsbereich_element = ET.SubElement(root, 'Geltungsbereich') - for gb in geltungsbereich_sections: - section_type = gb.abschnitttyp.abschnitttyp if gb.abschnitttyp else "text" - if section_type in ('tabelle', 'table'): - table = _parse_markdown_table(gb.inhalt) - if table is not None: - abschnitt_element = ET.SubElement(geltungsbereich_element, 'Abschnitt') - abschnitt_element.set('typ', section_type) - abschnitt_element.append(table) - else: - abschnitt_element = ET.SubElement(geltungsbereich_element, 'Abschnitt') - abschnitt_element.set('typ', section_type) - abschnitt_element.text = gb.inhalt - - einleitung_sections = dokument.einleitung_set.all().order_by('order') - if einleitung_sections: - einleitung_element = ET.SubElement(root, 'Einleitung') - for ei in einleitung_sections: - section_type = ei.abschnitttyp.abschnitttyp if ei.abschnitttyp else "text" - if section_type in ('tabelle', 'table'): - table = _parse_markdown_table(ei.inhalt) - if table is not None: - abschnitt_element = ET.SubElement(einleitung_element, 'Abschnitt') - abschnitt_element.set('typ', section_type) - abschnitt_element.append(table) - else: - abschnitt_element = ET.SubElement(einleitung_element, 'Abschnitt') - abschnitt_element.set('typ', section_type) - abschnitt_element.text = ei.inhalt - - ET.SubElement(root, 'Ziel').text = "" - ET.SubElement(root, 'Grundlagen').text = "" - - changelog_element = ET.SubElement(root, 'Changelog') - for cl in dokument.changelog.all().order_by('-datum'): - entry = ET.SubElement(changelog_element, 'Eintrag') - ET.SubElement(entry, 'Datum').text = cl.datum.strftime("%Y-%m-%d") - autoren = ET.SubElement(entry, 'Autoren') - for autor in cl.autoren.all(): - ET.SubElement(autoren, 'Autor').text = autor.name - ET.SubElement(entry, 'Aenderung').text = cl.aenderung - - anhaenge_element = ET.SubElement(root, 'Anhaenge') - ET.SubElement(anhaenge_element, 'Anhang').text = dokument.anhaenge - - ET.SubElement(root, 'Verantwortlich').text = "Information Security Management BIT" - ET.SubElement(root, 'Klassifizierung').text = "" - - glossar_element = ET.SubElement(root, 'Glossar') - - vorgaben_element = ET.SubElement(root, 'Vorgaben') - - for vorgabe in dokument.vorgaben.all().order_by('order'): - vorgabe_el = ET.SubElement(vorgaben_element, 'Vorgabe') - - ET.SubElement(vorgabe_el, 'Nummer').text = str(vorgabe.nummer) - ET.SubElement(vorgabe_el, 'Titel').text = vorgabe.titel - ET.SubElement(vorgabe_el, 'Thema').text = vorgabe.thema.name if vorgabe.thema else "" - - kurztext_sections = vorgabe.vorgabekurztext_set.all().order_by('order') - if kurztext_sections: - kurztext_element = ET.SubElement(vorgabe_el, 'Kurztext') - for kt in kurztext_sections: - section_type = kt.abschnitttyp.abschnitttyp if kt.abschnitttyp else "text" - if section_type in ('tabelle', 'table'): - table = _parse_markdown_table(kt.inhalt) - if table is not None: - abschnitt = ET.SubElement(kurztext_element, 'Abschnitt') - abschnitt.set('typ', section_type) - abschnitt.append(table) - else: - abschnitt = ET.SubElement(kurztext_element, 'Abschnitt') - abschnitt.set('typ', section_type) - abschnitt.text = kt.inhalt - - langtext_sections = vorgabe.vorgabelangtext_set.all().order_by('order') - if langtext_sections: - langtext_element = ET.SubElement(vorgabe_el, 'Langtext') - for lt in langtext_sections: - section_type = lt.abschnitttyp.abschnitttyp if lt.abschnitttyp else "text" - if section_type in ('tabelle', 'table'): - table = _parse_markdown_table(lt.inhalt) - if table is not None: - abschnitt = ET.SubElement(langtext_element, 'Abschnitt') - abschnitt.set('typ', section_type) - abschnitt.append(table) - else: - abschnitt = ET.SubElement(langtext_element, 'Abschnitt') - abschnitt.set('typ', section_type) - abschnitt.text = lt.inhalt - - referenz_element = ET.SubElement(vorgabe_el, 'Referenzen') - for ref in vorgabe.referenzen.all(): - ref_text = f"{ref.name_nummer}: {ref.name_text}" if ref.name_text else ref.name_nummer - ET.SubElement(referenz_element, 'Referenz').text = ref_text - - vorgabe_gueltigkeit = ET.SubElement(vorgabe_el, 'Gueltigkeit') - ET.SubElement(vorgabe_gueltigkeit, 'Von').text = vorgabe.gueltigkeit_von.strftime("%Y-%m-%d") if vorgabe.gueltigkeit_von else "" - ET.SubElement(vorgabe_gueltigkeit, 'Bis').text = vorgabe.gueltigkeit_bis.strftime("%Y-%m-%d") if vorgabe.gueltigkeit_bis else None - - checklistenfragen_element = ET.SubElement(vorgabe_el, 'Checklistenfragen') - for cf in vorgabe.checklistenfragen.all(): - ET.SubElement(checklistenfragen_element, 'Frage').text = cf.frage - - stichworte_element = ET.SubElement(vorgabe_el, 'Stichworte') - for stw in vorgabe.stichworte.all(): - ET.SubElement(stichworte_element, 'Stichwort').text = stw.stichwort + # Create a temporary root element to build the document + root = ET.Element('root') + build_dokument_xml_element(dokument, root) + + # Get the actual document element (first child of root) + doc_element = root[0] + + xml_str = ET.tostring(doc_element, encoding='unicode', method='xml') + xml_output = prettify_xml(xml_str) - xml_str = ET.tostring(root, encoding='unicode', method='xml') - xml_output = _prettify_xml(xml_str) - response = HttpResponse(xml_output, content_type='application/xml; charset=utf-8') response['Content-Disposition'] = f'attachment; filename="{dokument.nummer}.xml"' return response -def _prettify_xml(xml_string): - import xml.dom.minidom - dom = xml.dom.minidom.parseString(xml_string) - return dom.toprettyxml(indent=" ", encoding="UTF-8").decode('utf-8') - - @login_required def get_vorgabe_comments(request, vorgabe_id): """Get comments for a specific Vorgabe"""