This commit is contained in:
2025-08-12 23:53:44 +05:00
parent a882a81180
commit 6af7d54070
13 changed files with 462 additions and 431 deletions

View File

@@ -3,60 +3,104 @@
"""
import re
from pathlib import Path
from typing import List, Set, Optional
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.cadastral_numbers: Set[str] = set()
self.main_cadastral_number: Optional[str] = None
self.all_cadastral_numbers: Set[str] = set()
def extract_cadastral_numbers(self) -> Set[str]:
"""Извлекает кадастровые номера из XML файла"""
def extract_cadastral_data(self) -> Tuple[Optional[str], Set[str]]:
"""
Извлекает основной номер и все номера из XML файла
Возвращает (основной_номер, всеомера_в_файле)
"""
if not self.file_path.exists():
return set()
return None, set()
try:
# Парсим XML файл
tree = etree.parse(str(self.file_path))
root = tree.getroot()
# Используем улучшенный алгоритм извлечения
return self._extract_cadastral_numbers_enhanced(root)
# Находим все кадастровые номера в файле
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 set()
return None, set()
def _extract_cadastral_numbers_enhanced(self, root) -> Set[str]:
"""Улучшенный алгоритм извлечения кадастровых номеров"""
cadastral_numbers = set()
def _find_all_cadastral_numbers(self, root) -> Set[str]:
"""Находит все валидные кадастровые номера в XML"""
all_numbers = set()
# 1. Поиск по известным тегам
tags_to_search = ['cad_number', 'land_cad_number', 'cadastral_number', 'parcel_cad_number']
for tag in tags_to_search:
elements = root.xpath(f".//{tag}")
# Ищем по всем элементам
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):
cadastral_numbers.add(elem.text.strip())
return elem.text.strip()
# 2. Поиск в атрибутах
for elem in root.iter():
for attr_name, attr_value in elem.attrib.items():
if any(keyword in attr_name.lower() for keyword in ['cad', 'cadastral', 'кадастр']):
if self._is_valid_cadastral_number(attr_value):
cadastral_numbers.add(attr_value.strip())
# Если в приоритетных тегах не найдено, ищем по всем элементам
for elem in element.iter():
if elem.text and self._is_valid_cadastral_number(elem.text):
return elem.text.strip()
# 3. Regex поиск по тексту
text_content = etree.tostring(root, encoding='unicode', method='text')
if text_content:
regex_matches = re.findall(r'\d{1,2}:\d{1,2}:\d{6,8}:\d{1,5}', text_content)
for match in regex_matches:
if self._is_valid_cadastral_number(match):
cadastral_numbers.add(match)
self.cadastral_numbers = cadastral_numbers
return cadastral_numbers
return None
def _is_valid_cadastral_number(self, text: str) -> bool:
"""Проверяет, является ли строка валидным кадастровым номером"""
@@ -68,4 +112,4 @@ class XMLFileInfo:
return bool(re.match(pattern, text.strip()))
def __str__(self):
return f"XML файл: {self.file_path.name}, номеров: {len(self.cadastral_numbers)}"
return f"XML файл: {self.file_path.name}, основной номер: {self.main_cadastral_number}, всего номеров: {len(self.all_cadastral_numbers)}"