Files
kadastr14/models/xml_file_info.py
2025-08-12 23:53:44 +05:00

116 lines
5.1 KiB
Python
Raw 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.
"""
Модель для хранения информации об XML файле.
"""
import re
from pathlib import Path
from typing import List, Set, Optional, Tuple
from lxml import etree
class XMLFileInfo:
def __init__(self, file_path: str):
self.file_path = Path(file_path)
self.main_cadastral_number: Optional[str] = None
self.all_cadastral_numbers: Set[str] = set()
def extract_cadastral_data(self) -> Tuple[Optional[str], Set[str]]:
"""
Извлекает основной номер и все номера из XML файла
Возвращает (основной_номер, всеомера_в_файле)
"""
if not self.file_path.exists():
return None, set()
try:
tree = etree.parse(str(self.file_path))
root = tree.getroot()
# Находим все кадастровые номера в файле
all_numbers = self._find_all_cadastral_numbers(root)
# Определяем основной номер (из объекта)
main_number = self._find_main_cadastral_number(root, all_numbers)
self.main_cadastral_number = main_number
self.all_cadastral_numbers = all_numbers
return main_number, all_numbers
except Exception as e:
print(f"Ошибка при обработке файла {self.file_path}: {e}")
return None, set()
def _find_all_cadastral_numbers(self, root) -> Set[str]:
"""Находит все валидные кадастровые номера в XML"""
all_numbers = set()
# Ищем по всем элементам
for elem in root.iter():
if elem.text and self._is_valid_cadastral_number(elem.text):
all_numbers.add(elem.text.strip())
return all_numbers
def _find_main_cadastral_number(self, root, all_numbers: Set[str]) -> Optional[str]:
"""
Определяет основной кадастровый номер из объекта
Приоритет: object > другие контейнеры > первый найденный
"""
# 1. Ищем в объектах - высший приоритет
objects = root.xpath(".//object")
for obj in objects:
number = self._get_first_cadastral_from_element(obj)
if number and number in all_numbers:
return number
# 2. Ищем в других контейнерах объектов недвижимости
containers = [
'land_record', 'building_record', 'construction_record', 'flat_record',
'extract_about_property_land', 'extract_about_property_building',
'extract_about_property_flat', 'extract_about_property_construction',
'property_object', 'realty_object'
]
for container in containers:
elements = root.xpath(f".//{container}")
for elem in elements:
number = self._get_first_cadastral_from_element(elem)
if number and number in all_numbers:
return number
# 3. Если ничего не найдено в контейнерах, берем первый из всех найденных
if all_numbers:
return sorted(all_numbers)[0]
return None
def _get_first_cadastral_from_element(self, element) -> Optional[str]:
"""Находит первый кадастровый номер в элементе"""
# Приоритетные теги для поиска
priority_tags = ['cad_number', 'cadastral_number', 'land_cad_number', 'parcel_cad_number']
# Сначала ищем по приоритетным тегам
for tag in priority_tags:
elements = element.xpath(f".//{tag}")
for elem in elements:
if elem.text and self._is_valid_cadastral_number(elem.text):
return elem.text.strip()
# Если в приоритетных тегах не найдено, ищем по всем элементам
for elem in element.iter():
if elem.text and self._is_valid_cadastral_number(elem.text):
return elem.text.strip()
return None
def _is_valid_cadastral_number(self, text: str) -> bool:
"""Проверяет, является ли строка валидным кадастровым номером"""
if not text:
return False
# Улучшенный паттерн для российских кадастровых номеров
pattern = r'^\d{1,2}:\d{1,2}:\d{6,8}:\d{1,5}$'
return bool(re.match(pattern, text.strip()))
def __str__(self):
return f"XML файл: {self.file_path.name}, основной номер: {self.main_cadastral_number}, всего номеров: {len(self.all_cadastral_numbers)}"