core/homeassistant/components/ssdp/util.py

43 lines
1.4 KiB
Python

"""Util functions used by SSDP."""
from __future__ import annotations
from collections import defaultdict
from typing import Any
from defusedxml import ElementTree
# Adapted from http://stackoverflow.com/a/10077069
# to follow the XML to JSON spec
# https://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html
def etree_to_dict(tree: ElementTree) -> dict[str, dict[str, Any] | None]:
"""Convert an ETree object to a dict."""
# strip namespace
tag_name = tree.tag[tree.tag.find("}") + 1 :]
tree_dict: dict[str, dict[str, Any] | None] = {
tag_name: {} if tree.attrib else None
}
children = list(tree)
if children:
child_dict: dict[str, list] = defaultdict(list)
for child in map(etree_to_dict, children):
for k, val in child.items():
child_dict[k].append(val)
tree_dict = {
tag_name: {k: v[0] if len(v) == 1 else v for k, v in child_dict.items()}
}
dict_meta = tree_dict[tag_name]
if tree.attrib:
assert dict_meta is not None
dict_meta.update(("@" + k, v) for k, v in tree.attrib.items())
if tree.text:
text = tree.text.strip()
if children or tree.attrib:
if text:
assert dict_meta is not None
dict_meta["#text"] = text
else:
tree_dict[tag_name] = text
return tree_dict