Data Types

There is a global converter factory that is used during data binding between python and xml/json documents.

The converter ships with multiple adapters and will attempt to convert values according to the provided list of possible types but in case of an error it will fall back to str, even if that means violating the field typing definition.

A warning will also be raised in that case.

ConverterWarning: Failed to convert value `a` to one of [<class 'float'>]

Schema Types Mapping

Below you can find the mapping of data types between python and xml schema.

Python

XML Type

bool

boolean

bytes

hexBinary

base64Binary

Decimal

decimal

float

float

double

int

integer

nonPositiveInteger

negativeInteger

long

int

short

byte

nonNegativeInteger

unsignedLong

unsignedInt

unsignedShort

unsignedByte

positiveInteger

object

anyType

anySimpleType

QName

QName

NOTATION

str

string

anyURI

normalizedString

token

language

NMTOKEN

NMTOKENS

Name

NCName

ID

IDREF

IDREFS

ENTITIES

ENTITY

anyAtomicType

error

XmlDate

date

XmlDateTime

dateTime

dateTimeStamp

XmlDuration

duration

dayTimeDuration

yearMonthDuration

XmlPeriod

gYearMonth

gYear

gMonthDay

gMonth

gDay

XmlTime

time

enum.Enum

enumeration

Working with custom types

If you are working with a type that’s not supported or you want to override one of the builtin adapter’s behavior you can register you own.

>>> from dataclasses import dataclass, field
>>> from xsdata.formats.converter import Converter, converter
>>> from xsdata.formats.dataclass.parsers import XmlParser
>>> from xsdata.formats.dataclass.serializers import XmlSerializer
...
>>> class TheGoodFloat(float):
...     pass
...
>>> @dataclass
... class Example:
...     good: TheGoodFloat = field(metadata=dict(format="{:.2f}"))
...     bad: float
...
>>> class TheGoodFloatConverter(Converter):
...    def deserialize(self, value: str, **kwargs) -> str:
...        return round(float(value), 1)  # Even nicer
...
...    def serialize(self, value: float, **kwargs) -> str:
...        if kwargs["format"]:
...            return kwargs["format"].format(value)
...        return str(value)
...
>>> converter.register_converter(TheGoodFloat, TheGoodFloatConverter())
>>> serializer = XmlSerializer()
>>> output = serializer.render(Example(TheGoodFloat(10.983263748), -9.9827632))
>>> print(output)
<?xml version="1.0" encoding="UTF-8"?>
<Example><good>10.98</good><bad>-9.9827632</bad></Example>
>>> XmlParser().from_string(output)
Example(good=11.0, bad=-9.9827632)

Working with date strings

The builtin converter includes adapters for datetime.time, datetime.date and datetime.datetime.

Use the field metadata to set the target format according to the strftime() and strptime() Behavior

>>> import datetime as dt
>>> from dataclasses import dataclass, field
>>> from xsdata.formats.dataclass.serializers import XmlSerializer
>>> from xsdata.formats.dataclass.serializers.config import SerializerConfig
...
>>> @dataclass
... class Dates:
...     date: dt.date = field(metadata=dict(format="%d %B %Y"))
...     time: dt.time = field(metadata=dict(format="%H:%M"))
...     datetime: dt.datetime = field(metadata=dict(format="%d %B %Y %H:%M"))
...
>>> obj = Dates(
...     date=dt.date(2020, 1, 6),
...     time=dt.time(18, 15, 30),
...     datetime=dt.datetime(2020, 1, 6, 18, 15, 30)
... )
...
>>> config = SerializerConfig(pretty_print=True)
>>> serializer = XmlSerializer(config=config)
>>> print(serializer.render(obj))
<?xml version="1.0" encoding="UTF-8"?>
<Dates>
  <date>06 January 2020</date>
  <time>18:15</time>
  <datetime>06 January 2020 18:15</datetime>
</Dates>

Models generated by the cli from a schema definition use the builtin datatypes XmlDate, XmlTime and XmlDateTime instead because the datetime objects don’t support all the xml features like years bce.

The builtin date types have util methods to convert from and to datetime objects whenever possible.

>>> from dataclasses import dataclass
>>> from xsdata.formats.dataclass.serializers import XmlSerializer
>>> from xsdata.formats.dataclass.serializers.config import SerializerConfig
>>> from xsdata.models.datatype import XmlDate, XmlTime, XmlDateTime
...
>>> @dataclass
... class Dates:
...     date: XmlDate
...     time: XmlTime
...     datetime: XmlDateTime
...
>>> obj = Dates(
...     date=XmlDate(2020, 1, 6, 120),
...     time=XmlTime(18, 15, 30, 123000, 0),
...     datetime=XmlDateTime(2020, 1, 6, 18, 15, 30)
... )
...
>>> config = SerializerConfig(pretty_print=True)
>>> serializer = XmlSerializer(config=config)
>>> print(serializer.render(obj))
<?xml version="1.0" encoding="UTF-8"?>
<Dates>
  <date>2020-01-06+02:00</date>
  <time>18:15:30.123Z</time>
  <datetime>2020-01-06T18:15:30</datetime>
</Dates>

Working with binary data

xs:hexBinary and xs:base64Binary types are mapped to python bytes and are encoded/decoded with binascii and base64 modules.

>>> from dataclasses import dataclass, field
>>> from xsdata.formats.dataclass.serializers import XmlSerializer
>>> from xsdata.formats.dataclass.serializers.config import SerializerConfig
...
>>> @dataclass
... class Binary:
...     base_16: bytes = field(metadata=dict(format="base16"))
...     base_64: bytes = field(metadata=dict(format="base64"))
...
>>> obj = Binary(
...     base_16="xml".encode(),
...     base_64="binding".encode(),
... )
...
>>> config = SerializerConfig(pretty_print=True)
>>> serializer = XmlSerializer(config=config)
>>> print(serializer.render(obj))
<?xml version="1.0" encoding="UTF-8"?>
<Binary>
  <base_16>786D6C</base_16>
  <base_64>YmluZGluZw==</base_64>
</Binary>