feat: strukturierte Excel-Tabellen beim Glätten erhalten
This commit is contained in:
@@ -5,7 +5,7 @@ class DocumentationConfig(PluginConfig):
|
||||
name = "netbox_documentation"
|
||||
verbose_name = "NetBox Dokumentation"
|
||||
description = "Wiki und Office-Dokumentation direkt in NetBox"
|
||||
version = "0.5.3"
|
||||
version = "0.5.4"
|
||||
author = "LKE"
|
||||
base_url = "documentation"
|
||||
min_version = "4.0.0"
|
||||
|
||||
@@ -134,7 +134,7 @@ class ImportForm(forms.Form):
|
||||
required=False,
|
||||
label=help_label(
|
||||
"Excel-Tabellen glätten",
|
||||
"Übernimmt alle Zellen ohne Tabelle in Lesereihenfolge als dokumentartigen Text. Es werden keine Datensatz- oder Feldbezeichnungen erzeugt.",
|
||||
"Übernimmt normale Zellen ohne Tabelle als dokumentartigen Text. Nur in Excel ausdrücklich über Einfügen → Tabelle definierte Bereiche bleiben Tabellen.",
|
||||
),
|
||||
)
|
||||
category = forms.ModelChoiceField(
|
||||
|
||||
@@ -80,7 +80,7 @@ def _escape_markdown_text(value):
|
||||
|
||||
def _xlsx(content, flatten=False):
|
||||
from openpyxl import load_workbook
|
||||
workbook = load_workbook(BytesIO(content), read_only=True, data_only=True)
|
||||
workbook = load_workbook(BytesIO(content), read_only=not flatten, data_only=True)
|
||||
sections = []
|
||||
for sheet in workbook.worksheets:
|
||||
rows = [["" if cell is None else str(cell) for cell in row] for row in sheet.iter_rows(values_only=True)]
|
||||
@@ -88,7 +88,8 @@ def _xlsx(content, flatten=False):
|
||||
rows.pop()
|
||||
if not rows:
|
||||
continue
|
||||
sections.append(f"## {sheet.title}\n\n{_render_excel_rows(rows, flatten)}")
|
||||
rendered = _render_flattened_worksheet(sheet) if flatten else _render_excel_rows(rows)
|
||||
sections.append(f"## {sheet.title}\n\n{rendered}")
|
||||
if not sections:
|
||||
raise ImportFailure("Die Arbeitsmappe enthält keine Daten.")
|
||||
return ImportResult("\n\n".join(sections))
|
||||
@@ -131,7 +132,7 @@ def import_excel_sheets(upload, flatten=False) -> list[ExcelSheetResult]:
|
||||
if not rows and not images:
|
||||
continue
|
||||
if rows:
|
||||
markdown = _render_excel_rows(rows, flatten)
|
||||
markdown = _render_flattened_worksheet(sheet) if flatten else _render_excel_rows(rows)
|
||||
else:
|
||||
markdown = ""
|
||||
results.append(ExcelSheetResult(title=sheet.title, markdown=markdown, images=images))
|
||||
@@ -145,6 +146,51 @@ def slugify_filename(value):
|
||||
return value[:80] or "arbeitsblatt"
|
||||
|
||||
|
||||
def _render_flattened_worksheet(sheet):
|
||||
"""Flatten ordinary cells while preserving explicitly defined Excel tables."""
|
||||
from openpyxl.utils.cell import range_boundaries
|
||||
|
||||
table_ranges = []
|
||||
for table in sheet.tables.values():
|
||||
min_col, min_row, max_col, max_row = range_boundaries(table.ref)
|
||||
table_ranges.append((min_col, min_row, max_col, max_row))
|
||||
table_ranges.sort(key=lambda item: (item[1], item[0]))
|
||||
|
||||
def containing_table(row, column):
|
||||
for bounds in table_ranges:
|
||||
min_col, min_row, max_col, max_row = bounds
|
||||
if min_row <= row <= max_row and min_col <= column <= max_col:
|
||||
return bounds
|
||||
return None
|
||||
|
||||
blocks = []
|
||||
rendered_tables = set()
|
||||
for row_number in range(1, sheet.max_row + 1):
|
||||
ordinary_values = []
|
||||
tables_starting_here = []
|
||||
for column_number in range(1, sheet.max_column + 1):
|
||||
bounds = containing_table(row_number, column_number)
|
||||
if bounds:
|
||||
if bounds[1] == row_number and bounds not in rendered_tables:
|
||||
tables_starting_here.append(bounds)
|
||||
rendered_tables.add(bounds)
|
||||
continue
|
||||
value = sheet.cell(row=row_number, column=column_number).value
|
||||
if value not in (None, ""):
|
||||
ordinary_values.append(_escape_markdown_text(value))
|
||||
if ordinary_values:
|
||||
blocks.append(" \n".join(ordinary_values))
|
||||
for min_col, min_row, max_col, max_row in tables_starting_here:
|
||||
rows = []
|
||||
for table_row in sheet.iter_rows(
|
||||
min_row=min_row, max_row=max_row, min_col=min_col, max_col=max_col, values_only=True
|
||||
):
|
||||
rows.append(["" if value is None else str(value) for value in table_row])
|
||||
if rows:
|
||||
blocks.append(_render_excel_rows(rows, flatten=False))
|
||||
return "\n\n".join(blocks) or "_Keine Inhalte_"
|
||||
|
||||
|
||||
def _pdf(content):
|
||||
from pypdf import PdfReader
|
||||
reader = PdfReader(BytesIO(content))
|
||||
|
||||
Reference in New Issue
Block a user