It’s 2025, and I still can’t believe I have to say this — but handling XML, especially in Python, remains frustratingly painful.
Take this example: For the upcoming podcast feature of poketto.me, the app will generate a personalized podcast feed for each user, populated with text-to-speech versions of their saved content. Users can subscribe to their custom feed in any podcast app—pretty handy.
The feed itself isn’t complex: just an XML file hosted on a web server (in my case, a GCS bucket) containing metadata and links to episode MP3s. It just needs to comply with Apple’s
Podcast RSS Feed Requirements so podcast clients can parse it correctly.
Sounds simple, right?
Creating the feed XML with Python’s built-in ElementTree is straightforward enough — if all you do is initialize it:
rss = ET.Element(\"rss\", version=\"2.0\", attrib={
\"xmlns:itunes\": \"http://www.itunes.com/dtds/podcast-1.0.dtd\"
})
channel = ET.SubElement(rss, \"channel\")
ET.SubElement(channel, \"title\").text = feed_title
ET.SubElement(channel, \"link\").text = PODCAST_LINK
ET.SubElement(channel, \"description\").text = feed_title
\...
xml_bytes = ET.tostring(rss, encoding=\'utf-8\')
xml_string = xml_bytes.decode(\'utf-8\')
However… things get messy when you want to parse that XML later and append a new episode.
Here’s the naive approach:
tree = ET.ElementTree(ET.fromstring(feed_xml))
rss = tree.getroot()
channel = rss.find(\'channel\') \# type: ignore
ET.SubElement(channel, \"item\")
item = channel\[-1\]
ET.SubElement(item, \"title\").text = episode_title
\...
xml_bytes = ET.tostring(rss, encoding=\'utf-8\')
xml_string = xml_bytes.decode(\'utf-8\')
What does this give you?
Exhibit A: ElementTree renames the itunes namespace to ns0.
Technically valid — but practically useless, because most podcast clients choke on it.
So… what’s my hacky workaround?
Before saving the serialized XML, I literally search and replace ns0 with itunes:
xml_string = xml_string.replace(\'ns0\', \'itunes\')
Ugly? Yes.
Sustainable? Definitely not.
But it works — for now. 🤷 As long as you don’t want to have an episode titled “How if fixed the ns0-issue” of course 😅