This commit is contained in:
2025-06-03 00:16:16 +05:00
parent 56a554b500
commit fa10c8abbc
6 changed files with 151 additions and 139 deletions

208
main.py
View File

@@ -1,151 +1,83 @@
import xml.etree.ElementTree as ET
import openpyxl
import glob
import os
import xml.etree.ElementTree as ET
import pandas as pd
from pathlib import Path
HEADERS = [
"№ п/п",
"Раздел КПТР",
"Кадастровый номер",
"Кадастровый квартал",
"Вид объекта",
"Площадь ЗУ",
"Погрешность определения площади",
"наличие координат",
"Пояснения"
]
# === 🔧 НАСТРОЙКИ (меняйте под себя) ===
FOLDER_WITH_XMLS = r"C:\Users\jze9\Documents\work\git\kadastr12\test" # Папка с XML-файлами
OUTPUT_XLSX_FILE = r"C:\Users\jze9\Documents\work\git\kadastr12\result.xlsx" # Куда сохранить результат
# === ⛏ ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ===
def extract_text(elem, tag):
node = elem.find(f".//{tag}")
return node.text.strip() if node is not None and node.text else ""
def has_spatial(elem):
"""Проверяет наличие тега SpatialElement в рамках элемента."""
return "да" if elem.find(".//SpatialElement") is not None else "нет"
return elem.find(".//SpatialElement") is not None
def get_explanation(elem):
"""Ищет пояснения в тегах Explanation, ExplanationSection, NameSection"""
for tag in ["Explanation", "ExplanationSection", "NameSection"]:
sub = elem.find(f".//{tag}")
if sub is not None and sub.text:
return sub.text.strip()
return ""
def collect_explanations(elem):
return " ".join(e.text.strip() for e in elem.findall(".//Explanation") if e.text and e.text.strip())
def extract_fields(elem, tag):
"""
В зависимости от тега-объекта извлекает данные для строки:
2. Раздел КПТР устанавливается по тегу
3. Кадастровый номер
4. Кадастровый квартал
5. Вид объекта
6. Площадь ЗУ
7. Погрешность определения площади
8. наличие координат
9. Пояснения
"""
if tag in {"NewParcel", "SpecifyParcel"}:
section = "FormParcels" if tag=="NewParcel" else "SpecifyParcels"
cadastral_number = elem.attrib.get("Definition", "")
if cadastral_number.startswith(":"):
cadastral_number = cadastral_number[1:]
cadastral_block = (elem.findtext("CadastralBlock") or "").strip()
# Если внутри есть тег ObjectType берем его, иначе для ЗУ фиксированное значение
ot = elem.findtext("ObjectType")
object_type = ot.strip() if ot else "Земельный участок"
area = (elem.findtext("Area/Area") or "").strip()
inaccuracy = (elem.findtext("Area/Inaccuracy") or "").strip()
coords = has_spatial(elem)
explanation = get_explanation(elem)
return [None, section, cadastral_number, cadastral_block, object_type,
area, inaccuracy, coords, explanation]
def process_section(tree, tag, label, records, is_zemel=True):
section = tree.find(f".//{tag}")
if section is None:
return
subtag = next(iter(section), None)
if subtag is None:
return
for item in section.findall(f".//{subtag.tag}"):
rec = {
"Раздел КПТР": label,
"Кадастровый номер": extract_text(item, "CadastralNumber"),
"Кадастровый квартал": extract_text(item, "CadastralBlock"),
"Вид объекта": extract_text(item, "ObjectType"),
"Площадь ЗУ": extract_text(item.find("Area") or item, "Area") if is_zemel else "",
"Погрешность определения площади": extract_text(item.find("Area") or item, "Inaccuracy") if is_zemel else "",
"наличие координат": "да" if has_spatial(item) else "нет",
"Пояснения": collect_explanations(item),
}
records.append(rec)
elif tag == "CadastralErrorParcel":
# обрабатываем дочерний элемент CadastralErrorExistParcel
sub = elem.find("CadastralErrorExistParcel")
if sub is None:
return None
section = "CadastralErrorsParcels"
cadastral_number = sub.attrib.get("CadastralNumber", "")
cadastral_block = (sub.findtext("CadastralBlock") or "").strip()
area = (sub.findtext("Area/Area") or "").strip()
inaccuracy = (sub.findtext("Area/Inaccuracy") or "").strip()
coords = has_spatial(sub)
explanation = get_explanation(sub)
object_type = "Земельный участок"
return [None, section, cadastral_number, cadastral_block, object_type,
area, inaccuracy, coords, explanation]
# === 🚀 ОСНОВНОЙ КОД ===
def main():
records = []
for file in os.listdir(FOLDER_WITH_XMLS):
if not file.lower().endswith(".xml"):
continue
xml_path = os.path.join(FOLDER_WITH_XMLS, file)
try:
tree = ET.parse(xml_path)
except ET.ParseError as e:
print(f"❌ Ошибка в файле {file}: {e}")
continue
elif tag == "ExistParcel":
# элемент имеет атрибут CadastralNumber
section = "ExistParcels"
cadastral_number = elem.attrib.get("CadastralNumber", "")
cadastral_block = (elem.findtext("CadastralBlock") or "").strip()
area = (elem.findtext("Area/Area") or "").strip()
inaccuracy = (elem.findtext("Area/Inaccuracy") or "").strip()
coords = has_spatial(elem)
explanation = get_explanation(elem)
object_type = "Земельный участок"
return [None, section, cadastral_number, cadastral_block, object_type,
area, inaccuracy, coords, explanation]
root = tree.getroot()
process_section(root, "FormParcels", "Образование ЗУ", records)
process_section(root, "SpecifyParcels", "Уточнение ЗУ", records)
process_section(root, "CadastralErrorsParcels", "Исправление ЗУ", records)
process_section(root, "ExistNewObjectsRealty", "Уточнение ОКС", records, is_zemel=False)
process_section(root, "CadastralErrorsOKS", "Исправление ОКС", records, is_zemel=False)
elif tag == "ExistNewObjectRealty":
section = "ExistNewObjectsRealty"
cadastral_number = (elem.findtext("CadastralNumber") or "").strip()
ot = elem.findtext("ObjectType")
object_type = ot.strip() if ot else "Объект недвижимости"
cb_elem = elem.find("CadastralBlocks/CadastralBlock")
cadastral_block = cb_elem.text.strip() if cb_elem is not None else ""
# Пытаемся взять площадь из <Area/Area> или альтернативный тег
area = (elem.findtext("Area/Area") or elem.findtext("AreaInGKN") or "").strip()
inaccuracy = (elem.findtext("Area/Inaccuracy") or "").strip()
coords = has_spatial(elem)
explanation = get_explanation(elem)
return [None, section, cadastral_number, cadastral_block, object_type,
area, inaccuracy, coords, explanation]
if not records:
print("⚠️ Нет данных для экспорта.")
return
elif tag == "CadastralErrorOKS":
section = "CadastralErrorsOKS"
cadastral_number = elem.attrib.get("CadastralNumber", "")
cb_elem = elem.find("CadastralBlocks/CadastralBlock")
cadastral_block = cb_elem.text.strip() if cb_elem is not None else ""
# Возможно в данном разделе площадь находится в дочернем теге Area
area = (elem.findtext("Area/Area") or "").strip()
inaccuracy = (elem.findtext("Area/Inaccuracy") or "").strip()
coords = has_spatial(elem)
explanation = get_explanation(elem)
object_type = "Объект недвижимости"
return [None, section, cadastral_number, cadastral_block, object_type,
area, inaccuracy, coords, explanation]
else:
return None
for i, rec in enumerate(records, 1):
rec["№ п/п"] = i
def parse_all_stream(xml_file):
"""
Унифицированный итеративный парсинг.
Обрабатываются объекты, у которых тег относится к:
NewParcel, SpecifyParcel, CadastralErrorParcel, ExistParcel,
ExistNewObjectRealty, CadastralErrorOKS.
"""
TARGET_TAGS = {"NewParcel", "SpecifyParcel", "CadastralErrorParcel",
"ExistParcel", "ExistNewObjectRealty", "CadastralErrorOKS"}
context = ET.iterparse(xml_file, events=("end",))
for event, elem in context:
if elem.tag in TARGET_TAGS:
row = extract_fields(elem, elem.tag)
if row:
yield row
elem.clear()
def main(xml_folder, output_excel):
wb = openpyxl.Workbook()
ws = wb.active
ws.append(HEADERS)
row_num = 1
xml_files = glob.glob(os.path.join(xml_folder, "*.xml"))
for xml_file in xml_files:
for row in parse_all_stream(xml_file):
row[0] = row_num # заполняем № п/п
ws.append(row)
row_num += 1
wb.save(output_excel)
print(f"Excel-файл сохранён: {output_excel}")
df = pd.DataFrame(records, columns=[
"№ п/п",
"Раздел КПТР",
"Кадастровый номер",
"Кадастровый квартал",
"Вид объекта",
"Площадь ЗУ",
"Погрешность определения площади",
"наличие координат",
"Пояснения",
])
df.to_excel(OUTPUT_XLSX_FILE, index=False)
print(f"✔️ Файл успешно сохранён: {OUTPUT_XLSX_FILE}")
if __name__ == "__main__":
# Папка с XML-файлами, измените при необходимости.
main("./test", "kptr_table.xlsx")
main()