Model#

Root model#

A root model is bound to the root xml element with the tag matching the model tag or class name. If the corresponding element not found pydantic_xml.ParsingError exception is raised.

Model
class Company(BaseXmlModel, tag='company'):
    title: str
Document
<company>SpaceX</company>
{
    "title": "SpaceX"
}

Sub-models#

See models.

Namespaces#

You can declare the root model namespace by setting parameters ns and nsmap. where ns is the element namespace alias and nsmap is a namespace mapping. The namespace mapping is inherited by all the model field:

Model
class Company(
    BaseXmlModel,
    tag='company',
    ns='co',
    nsmap={'co': 'http://www.company.com/co'},
):
    founded: dt.date = element()
    website: HttpUrl = element(tag='web-size', ns='co')
Document
<co:company xmlns:co="http://www.company.com/co">
    <co:founded>2002-03-14</co:founded>
    <co:web-size>https://www.spacex.com</co:web-size>
</co:company>
{
    "founded": "2002-03-14",
    "website": "https://www.spacex.com"
}

Custom root type#

Pydantic supports so-called custom root type.

It works for primitive types:

Model
class WebSite(RootXmlModel):
    root: str


class Company(BaseXmlModel, tag='company'):
    website: WebSite
Document
<company>
    <website>https://www.spacex.com</website>
</company>
{
    "website": "https://www.spacex.com"
}

collection types:

Model
class Company(RootXmlModel, tag='company'):
    root: Dict[str, str]
Document
<company trade-name="SpaceX" type="Private"/>
{
    "trade-name": "SpaceX",
    "type":"Private"
}

and model types:

Model
class Socials(RootXmlModel, tag='socials'):
    root: List[HttpUrl] = element(tag='social')


class Contacts(RootXmlModel[Socials], tag='contacts'):
    pass
Document
<contacts>
    <socials>
        <social>https://www.linkedin.com/company/spacex</social>
        <social>https://twitter.com/spacex</social>
        <social>https://www.youtube.com/spacex</social>
    </socials>
</contacts>
[
    "https://www.linkedin.com/company/spacex",
    "https://twitter.com/spacex",
    "https://www.youtube.com/spacex"
]

Self-referencing models#

pydantic library supports self-referencing models. Within the model, you can refer to a not-yet-constructed model using a string.

Model
class Directory(BaseXmlModel, tag="Directory"):
    name: str = attr(name='Name')
    dirs: Optional[List['Directory']] = element(tag='Directory', default=None)
Document
<Directory Name="root">
    <Directory Name="etc">
        <Directory Name="ssh"/>
        <Directory Name="init"/>
    </Directory>
    <Directory Name="bin"/>
</Directory>
{
    "name": "root",
    "dirs": [
        {
            "name": "etc",
            "dirs": [
                {
                    "name": "ssh"
                },
                {
                    "name": "init"
                }
            ]
        },
        {
            "name": "bin"
        }
    ]
}

That allows you to parse hierarchical data structures:

model.py:

import pathlib
from typing import List, Optional

from pydantic_xml import BaseXmlModel, attr, element


class File(BaseXmlModel, tag="File"):
    name: str = attr(name='Name')
    mode: str = attr(name='Mode')


class Directory(BaseXmlModel, tag="Directory"):
    name: str = attr(name='Name')
    mode: str = attr(name='Mode')
    dirs: Optional[List['Directory']] = element(tag='Directory', default=None)
    files: Optional[List[File]] = element(tag='File', default_factory=list)


xml_doc = pathlib.Path('./doc.xml').read_text()

directory = Directory.from_xml(xml_doc)

json_doc = pathlib.Path('./doc.json').read_text()
assert directory == Directory.model_validate_json(json_doc)

doc.xml:

<Directory Name="root" Mode="rwxr-xr-x">
    <Directory Name="etc" Mode="rwxr-xr-x">
        <Directory Name="ssh" Mode="rwxr-xr-x"/>
        <File Name="passwd" Mode="-rw-r--r--"/>
        <File Name="hosts" Mode="-rw-r--r--"/>
    </Directory>
    <Directory Name="bin" Mode="rwxr-xr-x"/>
    <Directory Name="usr" Mode="rwxr-xr-x">
        <Directory Name="bin" Mode="rwxr-xr-x"/>
    </Directory>
</Directory>

doc.json:

{
    "name": "root",
    "mode": "rwxr-xr-x",
    "dirs": [
        {
            "name": "etc",
            "mode": "rwxr-xr-x",
            "dirs": [
                {
                    "name": "ssh",
                    "mode": "rwxr-xr-x"
                }
            ],
            "files": [
                {
                    "name": "passwd",
                    "mode": "-rw-r--r--"
                },
                {
                    "name": "hosts",
                    "mode": "-rw-r--r--"
                }
            ]
        },
        {
            "name": "bin",
            "mode": "rwxr-xr-x",
            "dirs": null,
            "files": []
        },
        {
            "name": "usr",
            "mode": "rwxr-xr-x",
            "dirs": [
                {
                    "name": "bin",
                    "mode": "rwxr-xr-x",
                    "dirs": null,
                    "files": []
                }
            ],
            "files": []
        }
    ],
    "files": []
}