# 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) -> TheGoodFloat:
    ...        return round(TheGoodFloat(value), 1)  # Even nicer
    ...
    ...    def serialize(self, value: TheGoodFloat, **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/%m/%Y"))
    ...     time: dt.time = field(metadata=dict(format="%H:%M"))
    ...     datetime: dt.datetime = field(metadata=dict(format="%d/%m/%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/01/2020</date>
      <time>18:15</time>
      <datetime>06/01/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, 123000000, 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>