dapper91 / pydantic-xml

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

Support for parsing XML structure with inherited namespace #173

Closed dtam95 closed 3 months ago

dtam95 commented 3 months ago

Hi, I am relatively new to XML and pydantic-xml so am just after some support with deserializing the particular structure below. Apologies if this is detailed in the docs somewhere, I've tried and failed many times to find a solution for this.

XML Being Parsed

<Foo xmlns="https://foo.com" xmlns:bar = "https://bar.com">
  <bar:Bar>
    <multiplier>0</multiplier>
    <value>10000</value>
  </bar:Bar>
</Foo>

Pydantic-xml Models

class Bar(BaseXmlModel, ns="bar", nsmap={"bar": "https://bar.com", "": "https://bar.com"}):
    multiplier: int = element(ns="")
    value: int = element(ns="")

class Foo(BaseXmlModel, nsmap={"": "https://foo.com", "bar": "https://bar.com"}):
    bar: Bar = element(tag="Bar")

Problem

When I attempt to parse the XML using the above model definitions like so

Foo.from_xml("""
<Foo xmlns="https://foo.com" xmlns:bar = "https://bar.com">
  <bar:Bar>
    <multiplier>0</multiplier>
    <value>10000</value>
  </bar:Bar>
</Foo>
""")

I receive the following error:

pydantic_core._pydantic_core.ValidationError: 2 validation errors for Foo
bar.multiplier
  [line -1]: Field required [type=missing, input_value={}, input_type=dict]
bar.value
  [line -1]: Field required [type=missing, input_value={}, input_type=dict]

However, if I explicitly define the namespace of the Bar elements like so, I am able to successfully parse the xml

Foo.from_xml("""
<Foo xmlns="https://foo.com" xmlns:bar = "https://bar.com">
  <bar:Bar>
    <bar:multiplier>0</bar:multiplier>
    <bar:value>10000</bar:value>
  </bar:Bar>
</Foo>
""")

Can anyone advise me where I am going wrong when attempting to parse the first XML structure?

I was under the impression that defining the elements of Bar as element(ns="") would allow the original XML structure to be parsed using the implicit namespace rather than needing it to be explicitly defined on all the elements.

dtam95 commented 3 months ago

Closing this issue as I've now got this working with the following model definition (there was no need to modify the nsmap). I appear to have misunderstood the way namespacing inheritance works in xml.

class Bar(BaseXmlModel, ns="bar", nsmap={"": "https://foo.com", "bar": "https://bar.com"}):
    multiplier: int = element(ns="")
    value: int = element(ns="")

class Foo(BaseXmlModel, nsmap={"": "https://foo.com", "bar": "https://bar.com"}):
    bar: Bar = element(tag="Bar")