Parse XML namespaces into array not dict

Bug report.

One of my devices sends XML with multiple xmlns attributes. In a dict these get lost:

import io
import xml.etree.ElementTree as ET

xml = '''<?xml version="1.0" encoding="utf-8" ?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
  <X_Rhapsody-Extension xmlns="http://www.real.com/rhapsody/xmlns/upnp-1-0" />
  <qq:X_QPlay_SoftwareCapability xmlns:qq="http://www.tencent.com" />
</root>'''

print(dict(elem for (event, elem) in ET.iterparse(io.StringIO(xml), events=['start-ns'])).values())

print([el[1][1] for el in ET.iterparse(io.StringIO(xml), events=['start-ns'])])

Suggestion

diff --git pa_dlna/upnp/xml.py pa_dlna/upnp/xml.py
index c6fe582..9767d1e 100644
--- pa_dlna/upnp/xml.py
+++ pa_dlna/upnp/xml.py
@@ -27,9 +27,9 @@ class UPnPXMLError(UPnPError): pass
 
 # XML helper functions.
 @functools_cache
-def namespace_as_dict(xml):
-    return dict(elem for (event, elem) in ET.iterparse(
-            io.StringIO(xml), events=['start-ns']))
+def namespaces(xml):
+    return [ns for (_event, (_qualifier, ns)) in ET.iterparse(
+            io.StringIO(xml), events=['start-ns'])]
 
 def upnp_org_etree(xml):
     """Return the element tree and UPnP namespace from an xml string."""
@@ -209,8 +209,8 @@ class UPnPNamespace:
     def __init__(self, xml, prefix):
         """The first namespace in 'xml' starting with 'prefix'."""
 
-        ns = namespace_as_dict(xml)
-        for uri in ns.values():
+        ns = namespaces(xml)
+        for uri in ns:
             if uri.startswith(prefix):
                 self.uri = uri
                 return

I don't know what @functools_cache does, but maybe it's useful to inline the code to not create the temporary array and iterate two times.

Your environment.

  • pa-dlna version: 0.14
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information