osmapi.xmlbuilder

 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("&", "&amp;")
66        .replace('"', "&quot;")
67        .replace("<", "&lt;")
68        .replace(">", "&gt;")
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