dapper91 / pydantic-xml

python xml for humans
https://pydantic-xml.readthedocs.io
The Unlicense
141 stars 14 forks source link

Issues with Namespace Handling in pydantic-xml When Parsing XML #188

Closed ndmitri closed 2 months ago

ndmitri commented 2 months ago

I am experiencing issues with parsing XML using the pydantic-xml library, specifically when namespaces are involved. The parsing works correctly without namespaces, but fails when I include nsmap to handle namespaces.

Code Example Without nsmap (Works Correctly)

from pydantic_xml import BaseXmlModel, element
from typing import List

class InstList(BaseXmlModel, tag='Inst-list'):
    name: int = element()

class InstItems(BaseXmlModel, tag='inst-items'):
    inst_list: List[InstList]

class OspfItems(BaseXmlModel, tag='ospf-items'):
    inst_items: InstItems

class System(BaseXmlModel):
    ospf_items: OspfItems

xml_data = """
<System><ospf-items><inst-items><Inst-list><name>100</name></Inst-list><Inst-list><name>200</name></Inst-list></inst-items></ospf-items></System>
"""

system = System.from_xml(source=xml_data)
print(system)

Output

ospf_items=OspfItems(inst_items=InstItems(inst_list=[InstList(name=100), InstList(name=200)]))

Code Example With nsmap (Fails)

class System(BaseXmlModel, nsmap={'': 'http://cisco.com/ns/yang/cisco-nx-os-device'}):
    ospf_items: OspfItems

xml_data = """
<System xmlns="http://cisco.com/ns/yang/cisco-nx-os-device"><ospf-items><inst-items><Inst-list><name>100</name></Inst-list><Inst-list><name>200</name></Inst-list></inst-items></ospf-items></System>
"""

system = System.from_xml(source=xml_data)
print(system)

Error Message:

Traceback (most recent call last):
  File "xml.py", line 54, in <module>
    system = System.from_xml(source=xml_data)
  ...
pydantic_core._pydantic_core.ValidationError: 1 validation error for System
ospf_items.inst_items
  [line 2]: Field required [type=missing, input_value={}, input_type=dict]

Expected Behavior I expect the XML parsing to handle namespaces similarly to how it handles non-namespaced XML.

Actual Behavior When namespaces are introduced, the parsing fails with a ValidationError indicating that required fields are missing.

Environment Python version: 3.10 pydantic-xml version: 2.9.2

Questions Is there a specific way to configure nsmap or related settings to handle namespaces correctly in this context? Are there known issues with namespace handling in pydantic-xml that might be causing this behavior? Any help or guidance on resolving this namespace handling issue would be greatly appreciated!

dapper91 commented 2 months ago

@ndmitri Hi,

Namespace map is not inherited by nested models, so namespace map must be defined explicitly for each sub-model. This code should work correctly:

>>> from pydantic_xml import BaseXmlModel, element
>>> from typing import List
>>> 
>>> NSMAP = {'': 'http://cisco.com/ns/yang/cisco-nx-os-device'}
>>> 
>>> class InstList(BaseXmlModel, tag='Inst-list', nsmap=NSMAP):
...     name: int = element()
... 
>>> class InstItems(BaseXmlModel, tag='inst-items', nsmap=NSMAP):
...     inst_list: List[InstList]
... 
>>> class OspfItems(BaseXmlModel, tag='ospf-items', nsmap=NSMAP):
...     inst_items: InstItems
... 
>>> class System(BaseXmlModel, nsmap=NSMAP):
...     ospf_items: OspfItems
... 
>>> xml_data = """
... <System xmlns="http://cisco.com/ns/yang/cisco-nx-os-device">
...     <ospf-items>
...         <inst-items>
...             <Inst-list>
...                 <name>100</name>
...                 </Inst-list>
...             <Inst-list>
...                 <name>200</name>
...             </Inst-list>
...         </inst-items>
...     </ospf-items>
... </System>
... """
>>> 
>>> system = System.from_xml(source=xml_data)
>>> print(system)
ospf_items=OspfItems(inst_items=InstItems(inst_list=[InstList(name=100), InstList(name=200)]))
ndmitri commented 2 months ago

@dapper91, thank you very much for explaining. :)