[FEAT] XML support #841: Add XML output type, formatter, and utilities; tests included
parent
48e7fd8a79
commit
7a62ef4b5b
@ -0,0 +1,40 @@
|
||||
import xml.etree.ElementTree as ET
|
||||
from typing import Any
|
||||
|
||||
def dict_to_xml(tag: str, d: dict) -> ET.Element:
|
||||
"""Convert a dictionary to an XML Element."""
|
||||
elem = ET.Element(tag)
|
||||
for key, val in d.items():
|
||||
child = ET.Element(str(key))
|
||||
if isinstance(val, dict):
|
||||
child.append(dict_to_xml(str(key), val)) # FIX: use append, not extend
|
||||
elif isinstance(val, list):
|
||||
for item in val:
|
||||
if isinstance(item, dict):
|
||||
child.append(dict_to_xml(str(key), item))
|
||||
else:
|
||||
item_elem = ET.Element("item")
|
||||
item_elem.text = str(item)
|
||||
child.append(item_elem)
|
||||
else:
|
||||
child.text = str(val)
|
||||
elem.append(child)
|
||||
return elem
|
||||
|
||||
def to_xml_string(data: Any, root_tag: str = "root") -> str:
|
||||
"""Convert a dict or list to an XML string."""
|
||||
if isinstance(data, dict):
|
||||
elem = dict_to_xml(root_tag, data)
|
||||
elif isinstance(data, list):
|
||||
elem = ET.Element(root_tag)
|
||||
for item in data:
|
||||
if isinstance(item, dict):
|
||||
elem.append(dict_to_xml("item", item))
|
||||
else:
|
||||
item_elem = ET.Element("item")
|
||||
item_elem.text = str(item)
|
||||
elem.append(item_elem)
|
||||
else:
|
||||
elem = ET.Element(root_tag)
|
||||
elem.text = str(data)
|
||||
return ET.tostring(elem, encoding="unicode")
|
@ -0,0 +1,45 @@
|
||||
import pytest
|
||||
from swarms.utils.xml_utils import dict_to_xml, to_xml_string
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
def test_dict_to_xml_simple():
|
||||
d = {"foo": "bar", "baz": 1}
|
||||
elem = dict_to_xml("root", d)
|
||||
xml_str = ET.tostring(elem, encoding="unicode")
|
||||
assert "<foo>bar</foo>" in xml_str
|
||||
assert "<baz>1</baz>" in xml_str
|
||||
|
||||
def test_dict_to_xml_nested():
|
||||
d = {"foo": {"bar": "baz"}}
|
||||
elem = dict_to_xml("root", d)
|
||||
xml_str = ET.tostring(elem, encoding="unicode")
|
||||
assert "<foo>" in xml_str and "<bar>baz</bar>" in xml_str
|
||||
|
||||
def test_dict_to_xml_list():
|
||||
d = {"items": [1, 2, 3]}
|
||||
elem = dict_to_xml("root", d)
|
||||
xml_str = ET.tostring(elem, encoding="unicode")
|
||||
assert xml_str.count("<item>") == 3
|
||||
assert "<item>1</item>" in xml_str
|
||||
|
||||
def test_to_xml_string_dict():
|
||||
d = {"foo": "bar"}
|
||||
xml = to_xml_string(d, root_tag="root")
|
||||
assert xml.startswith("<root>") and "<foo>bar</foo>" in xml
|
||||
|
||||
def test_to_xml_string_list():
|
||||
data = [{"a": 1}, {"b": 2}]
|
||||
xml = to_xml_string(data, root_tag="root")
|
||||
assert xml.startswith("<root>") and xml.count("<item>") == 2
|
||||
|
||||
def test_to_xml_string_scalar():
|
||||
xml = to_xml_string("hello", root_tag="root")
|
||||
assert xml == "<root>hello</root>"
|
||||
|
||||
def test_dict_to_xml_edge_cases():
|
||||
d = {"empty": [], "none": None, "bool": True}
|
||||
elem = dict_to_xml("root", d)
|
||||
xml_str = ET.tostring(elem, encoding="unicode")
|
||||
assert "<empty />" in xml_str or "<empty></empty>" in xml_str
|
||||
assert "<none>None</none>" in xml_str
|
||||
assert "<bool>True</bool>" in xml_str
|
Loading…
Reference in new issue