Files
kadastr-17/services/data_loader.py
2026-03-25 13:38:54 +05:00

131 lines
5.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Загрузка исходных данных: Таблица 1 (КИ), Таблица 2, Таблица 3, индекс MIF-файлов."""
import zipfile
from pathlib import Path
from xml.etree import ElementTree as ET
from openpyxl import load_workbook
def load_ki(path: str) -> dict:
"""Таблица 1: {название_поля → значение}."""
wb = load_workbook(path, data_only=True)
ws = wb.active
ki = {}
for row in ws.iter_rows(values_only=True):
if row[0] is not None and row[1] is not None:
ki[str(row[0]).strip()] = str(row[1]).strip()
return ki
def ki_val(ki: dict, keyword: str) -> str:
"""Найти значение в словаре КИ по подстроке ключа (без учёта регистра)."""
for k, v in ki.items():
if keyword.lower() in k.lower():
return v
return ""
def load_table2(path: str) -> list:
"""Таблица 2: список строк (кортежи). Заголовок и пустые строки пропускаются."""
wb = load_workbook(path, data_only=True)
ws = wb.active
rows = []
for i, row in enumerate(ws.iter_rows(values_only=True)):
if i == 0:
continue
if all(v is None for v in row[:5]):
continue
rows.append(row)
return rows
def build_mif_index(mif_dir: str) -> dict:
"""Индекс MIF-файлов: stem → полный путь."""
index = {}
for p in Path(mif_dir).rglob("*.mif"):
index[p.stem] = str(p)
return index
def load_table3(path: str):
"""
Таблица 3 (для схем): возвращает два словаря (images, scales).
images: {zu_name → PNG-байты}
scales: {zu_name → строка масштаба, например 'Масштаб: 1:150'}
Структура xlsx: каждый блок = 3 строки.
Строка 1: ('вид он', None, None, 'зу', 'название файла', zu_name)
Строка 2: изображение якорено здесь
Строка 3: масштаб в столбце A (c1)
Изображения извлекаются прямо из zip-архива xlsx через drawing/rels.
"""
# --- Читаем имена ZU и масштабы по строкам (1-based) ---
wb = load_workbook(path, data_only=True)
ws = wb.active
zu_by_row = {} # 1-based строка заголовка → zu_name
scales = {} # zu_name → масштаб (строка из c1 третьей строки блока)
for i, row in enumerate(ws.iter_rows(values_only=True), start=1):
zu_name = row[5] if len(row) > 5 else None
if zu_name and str(zu_name).strip():
zu_name = str(zu_name).strip()
zu_by_row[i] = zu_name
# масштаб — третья строка блока (header+2)
scale_val = ws.cell(i + 2, 1).value
if scale_val:
scales[zu_name] = str(scale_val).strip()
# --- Читаем привязку картинок из drawing XML ---
_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
_XDR = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
_A = "http://schemas.openxmlformats.org/drawingml/2006/main"
ns = {"xdr": _XDR, "a": _A, "r": _R}
result = {}
with zipfile.ZipFile(path, "r") as z:
names = z.namelist()
# Найдём все drawing-файлы
drawing_files = [n for n in names if n.startswith("xl/drawings/drawing") and n.endswith(".xml")]
for draw_path in drawing_files:
rels_path = draw_path.replace("xl/drawings/", "xl/drawings/_rels/") + ".rels"
if rels_path not in names:
continue
rels_root = ET.fromstring(z.read(rels_path))
rid_to_media = {
rel.get("Id"): rel.get("Target").split("/")[-1]
for rel in rels_root
}
draw_root = ET.fromstring(z.read(draw_path))
for anchor in draw_root:
from_el = anchor.find(f"{{{_XDR}}}from")
if from_el is None:
continue
row_0b = int(from_el.find(f"{{{_XDR}}}row").text) # 0-based
img_row_1b = row_0b + 1 # 1-based
blip = anchor.find(f".//{{{_A}}}blip")
if blip is None:
continue
rid = blip.get(f"{{{_R}}}embed")
media_filename = rid_to_media.get(rid)
if not media_filename:
continue
media_path = f"xl/media/{media_filename}"
if media_path not in names:
continue
# Ищем ближайшую ZU-строку заголовка, которая <= img_row_1b
header_row = max(
(r for r in zu_by_row if r <= img_row_1b),
default=None,
)
if header_row is None:
continue
zu_name = zu_by_row[header_row]
result[zu_name] = z.read(media_path)
return result, scales