File size: 3,369 Bytes
57cf043
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import os

from bs4 import BeautifulSoup

from components.parser.xml.constants import (
    ACTUAL_STATUSES,
    EXCLUDE_OWNERS,
    NAME_TAG,
    OWNER_TAGS,
    STATUS_TAG,
    USEFUL_STATUSES,
)
from components.parser.xml.structures import ParsedXML


class XMLInfoParser:
    """
    Класс для парсинга основной информации из xml файлов.
    """

    def __init__(self, soup: BeautifulSoup, filepath: os.PathLike):
        """
        Инициализация парсера.

        Args:
            soup: BeautifulSoup - суп, содержащий xml документ
            filepath: os.PathLike - путь к файлу
        """
        self.filepath = filepath
        self.soup = soup

    def parse(self) -> ParsedXML | None:
        """
        Парсинг основной информации о xml файле.

        Returns:
            ParsedXML - информация о xml файле
        """
        status = self._extract_info_value(STATUS_TAG)
        owner = self._extract_info_recurse(OWNER_TAGS, EXCLUDE_OWNERS)
        name = self._extract_info_value(NAME_TAG)

        if (name == '') and (status == '') and (owner == ''):
            status = ACTUAL_STATUSES[0]
            owner = '-'
            name = self.filepath.stem

        if status not in USEFUL_STATUSES:
            return None

        return ParsedXML(status=status, owner=owner, name=name, filename=self.filepath)

    def _extract_info_value(self, key: str) -> str:
        """
        Извлечение значения из xml по тегу с использованием BeautifulSoup.

        Args:
            key: str - тег, по которому будет производиться поиск. Либо название документа, либо статус, либо владелец

        Returns:
            str - значение статуса, владельца или названия документа
        """
        # Ищем тег в супе
        key_tag = self.soup.find(string=key)
        if not key_tag:
            return ''

        # Ищем следующий текстовый тег после ключевого
        next_tag = key_tag.find_next('w:t')
        if not next_tag:
            return ''

        return next_tag.get_text()

    def _extract_info_recurse(
        self,
        keys: list[str],
        excluding_values: list[str] | None = None,
    ) -> str:
        """
        Извлечение значения из xml по нескольким тегам с использованием BeautifulSoup.

        Args:
            keys: list[str] - список тегов, по которым будет производиться поиск
            excluding_values: list[str] | None - список значений, которые нужно исключить из результата

        Returns:
            str - значение статуса, владельца или названия документа
        """
        result = []
        for key in keys:
            value = self._extract_info_value(key)
            if excluding_values and (value in excluding_values):
                continue
            if value:
                result.append(value)
        return '/'.join(reversed(result))