95 lines
3.7 KiB
Python
95 lines
3.7 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
from xml.etree import ElementTree as ET
|
|
|
|
XML_LANG = "{http://www.w3.org/XML/1998/namespace}lang"
|
|
|
|
|
|
def _text(value: Any) -> str:
|
|
return str(value or "").strip()
|
|
|
|
|
|
def _labels(node: ET.Element) -> dict[str, dict[str, str]]:
|
|
result = {
|
|
"ru": {"label": "", "description": "", "short": ""},
|
|
"en": {"label": "", "description": "", "short": ""},
|
|
}
|
|
for label in node.findall("./label"):
|
|
language = _text(label.attrib.get(XML_LANG) or label.attrib.get("lang") or "ru").lower()
|
|
if language not in result:
|
|
continue
|
|
result[language] = {
|
|
"label": _text(label.text),
|
|
"description": _text(label.attrib.get("description")),
|
|
"short": _text(label.attrib.get("short")),
|
|
}
|
|
return result
|
|
|
|
|
|
def _merge_entry(target: dict[str, Any], source: dict[str, Any]) -> None:
|
|
for language in ("ru", "en"):
|
|
current = target.setdefault(language, {"label": "", "description": "", "short": ""})
|
|
incoming = source.get(language, {})
|
|
for key in ("label", "description", "short"):
|
|
if not current.get(key) and incoming.get(key):
|
|
current[key] = incoming[key]
|
|
|
|
|
|
def parse_navigation_labels_xml(content: bytes | str) -> dict[str, Any]:
|
|
raw = content.encode("utf-8") if isinstance(content, str) else content
|
|
root = ET.fromstring(raw)
|
|
columns: dict[str, dict[str, Any]] = {}
|
|
by_section: dict[str, dict[str, dict[str, Any]]] = {}
|
|
sections: dict[str, dict[str, Any]] = {}
|
|
|
|
for item in root.findall(".//list//item[@section]"):
|
|
section = _text(item.attrib.get("section"))
|
|
if section:
|
|
entry = _labels(item)
|
|
target = sections.setdefault(section, {})
|
|
_merge_entry(target, entry)
|
|
|
|
for columns_node in root.findall(".//columns"):
|
|
section_names = [part for part in _text(columns_node.attrib.get("sections")).split() if part]
|
|
for index, cell in enumerate(columns_node.findall("./cell")):
|
|
ref = _text(cell.attrib.get("ref"))
|
|
labels = _labels(cell)
|
|
if not ref:
|
|
ru = labels.get("ru", {}).get("label", "").casefold()
|
|
en = labels.get("en", {}).get("label", "").casefold()
|
|
if ru in {"игрок", "хоккеист"} or en == "player":
|
|
ref = "player"
|
|
elif ru in {"клуб", "команда"} or en == "team":
|
|
ref = "team"
|
|
elif ru == "№" or en in {"№", "no.", "number"}:
|
|
ref = "number"
|
|
elif index == 0:
|
|
ref = "rank"
|
|
else:
|
|
continue
|
|
entry = {
|
|
**labels,
|
|
"datatype": _text(cell.attrib.get("datatype")),
|
|
"sortable": _text(cell.attrib.get("sortable")),
|
|
"default": _text(cell.attrib.get("default")),
|
|
}
|
|
global_entry = columns.setdefault(ref, {})
|
|
_merge_entry(global_entry, entry)
|
|
for key in ("datatype", "sortable", "default"):
|
|
if not global_entry.get(key) and entry.get(key):
|
|
global_entry[key] = entry[key]
|
|
for section in section_names:
|
|
section_entry = by_section.setdefault(section, {}).setdefault(ref, {})
|
|
_merge_entry(section_entry, entry)
|
|
for key in ("datatype", "sortable", "default"):
|
|
if not section_entry.get(key) and entry.get(key):
|
|
section_entry[key] = entry[key]
|
|
|
|
return {
|
|
"available": bool(columns or sections),
|
|
"columns": columns,
|
|
"columns_by_section": by_section,
|
|
"sections": sections,
|
|
}
|