1from typing import Any, Optional, TYPE_CHECKING
2from xml.dom.minidom import Element
3
4if TYPE_CHECKING:
5 from .OsmApi import OsmApi
6
7
8def _xml_build( # noqa: C901
9 element_type: str,
10 element_data: dict[str, Any],
11 with_headers: bool = True,
12 *,
13 data: "OsmApi",
14) -> bytes:
15 xml = ""
16 if with_headers:
17 xml += '<?xml version="1.0" encoding="UTF-8"?>\n'
18 xml += '<osm version="0.6" generator="'
19 xml += data._created_by + '">'
20 xml += "\n"
21
22 # <element attr="val">
23 xml += " <" + element_type
24 if "id" in element_data:
25 xml += ' id="' + str(element_data["id"]) + '"'
26 if "lat" in element_data:
27 xml += ' lat="' + str(element_data["lat"]) + '"'
28 if "lon" in element_data:
29 xml += ' lon="' + str(element_data["lon"]) + '"'
30 if "version" in element_data:
31 xml += ' version="' + str(element_data["version"]) + '"'
32 visible_str = str(element_data.get("visible", True)).lower()
33 xml += ' visible="' + visible_str + '"'
34 if element_type in ["node", "way", "relation"]:
35 xml += ' changeset="' + str(data._current_changeset_id) + '"'
36 xml += ">\n"
37
38 # <tag... />
39 for k, v in element_data.get("tag", {}).items():
40 xml += ' <tag k="' + _xml_encode(k)
41 xml += '" v="' + _xml_encode(v) + '"/>\n'
42
43 # <member... />
44 for member in element_data.get("member", []):
45 xml += ' <member type="' + member["type"]
46 xml += '" ref="' + str(member["ref"])
47 xml += '" role="' + _xml_encode(member["role"])
48 xml += '"/>\n'
49
50 # <nd... />
51 for ref in element_data.get("nd", []):
52 xml += ' <nd ref="' + str(ref) + '"/>\n'
53
54 # </element>
55 xml += " </" + element_type + ">\n"
56
57 if with_headers:
58 xml += "</osm>\n"
59
60 return xml.encode("utf8")
61
62
63def _xml_encode(text: str) -> str:
64 return (
65 text.replace("&", "&")
66 .replace('"', """)
67 .replace("<", "<")
68 .replace(">", ">")
69 )
70
71
72def _get_xml_value(dom_element: Element, tag: str) -> Optional[str]:
73 try:
74 elem = dom_element.getElementsByTagName(tag)[0]
75 return elem.firstChild.nodeValue # type: ignore[union-attr]
76 except Exception:
77 return None