Skip to content

# utils

## `xsdata.formats.dataclass.parsers.utils`

### `PendingCollection`

Bases: `UserList`

An iterable implementation of parsed values.

The values are parsed individually in the end we need to convert it to a tuple or a list based on the mutability setting of the data class.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`initlist` | `Iterable | None` | An initial list of values or None | required
`factory` | `Callable | None` | A callable factory for the values when the node parse has finished. | required

Source code in `xsdata/formats/dataclass/parsers/utils.py`

    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47

    class PendingCollection(UserList):
        """An iterable implementation of parsed values.

        The values are parsed individually in the end we
        need to convert it to a tuple or a list based on
        the mutability setting of the data class.

        Args:
            initlist: An initial list of values or None
            factory: A callable factory for the values
                when the node parse has finished.

        """

        def __init__(self, initlist: Iterable | None, factory: Callable | None):
            """Initialize the pending collection."""
            super().__init__(initlist)
            self.factory = factory or list

        def evaluate(self) -> Iterable[Any]:
            """Evaluate the values factory and return the result.

            Returns:
                A list or tuple or set of values
            """
            return self.factory(self.data)

#### `__init__(initlist, factory)`

Initialize the pending collection.

Source code in `xsdata/formats/dataclass/parsers/utils.py`

    36
    37
    38
    39

    def __init__(self, initlist: Iterable | None, factory: Callable | None):
        """Initialize the pending collection."""
        super().__init__(initlist)
        self.factory = factory or list

#### `evaluate()`

Evaluate the values factory and return the result.

Returns:

Type | Description
--- | ---
`Iterable[Any]` | A list or tuple or set of values

Source code in `xsdata/formats/dataclass/parsers/utils.py`

    41
    42
    43
    44
    45
    46
    47

    def evaluate(self) -> Iterable[Any]:
        """Evaluate the values factory and return the result.

        Returns:
            A list or tuple or set of values
        """
        return self.factory(self.data)

### `ParserUtils`

Random parser util functions.

Source code in `xsdata/formats/dataclass/parsers/utils.py`

     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258

    class ParserUtils:
        """Random parser util functions."""

        @classmethod
        def xsi_type(cls, attrs: dict, ns_map: dict) -> str | None:
            """Parse the xsi:type attribute value if present.

            Args:
                attrs: The element attributes
                ns_map: The element namespace prefix-URI map

            Returns:
                The xsi:type attribute value or None
            """
            xsi_type = attrs.get(QNames.XSI_TYPE)
            if not xsi_type:
                return None

            namespace, name = QNameConverter.resolve(xsi_type, ns_map)
            return build_qname(namespace, name)

        @classmethod
        def xsi_nil(cls, attrs: dict) -> bool | None:
            """Return whether xsi:nil attribute value.

            Args:
                attrs: The element attributes

            Returns:
                The bool value or None if it doesn't exist.
            """
            xsi_nil = attrs.get(QNames.XSI_NIL)
            return xsi_nil == constants.XML_TRUE if xsi_nil else None

        @classmethod
        def parse_var(
            cls,
            meta: XmlMeta,
            var: XmlVar,
            config: ParserConfig,
            value: Any,
            ns_map: dict | None = None,
            default: Any = None,
            types: Sequence[type] | None = None,
            tokens_factory: Callable | None = None,
            format: str | None = None,
        ) -> Any:
            """Convert a value to a python primitive type.

            Args:
                meta: The xml meta instance
                var: The xml var instance
                config: The parser config instance
                value: A primitive value or a list of primitive values
                ns_map: The element namespace prefix-URI map
                default: Override the var default value
                types: Override the var types
                tokens_factory: Override the var tokens factory
                format: Override the var format

            Returns:
                The converted value or values.
            """
            try:
                value = cls.parse_value(
                    value=value,
                    types=types or var.types,
                    default=default or var.default,
                    ns_map=ns_map,
                    tokens_factory=tokens_factory or var.tokens_factory,
                    format=format or var.format,
                )
            except ConverterError as ex:
                message = (
                    "Failed to convert value for "
                    f"`{meta.clazz.__qualname__}.{var.name}`\n  {ex}"
                )
                if config.fail_on_converter_warnings:
                    raise ParserError(message)

                warnings.warn(message, ConverterWarning)

            return value

        @classmethod
        def parse_value(
            cls,
            value: Any,
            types: Sequence[type],
            default: Any | None = None,
            ns_map: dict | None = None,
            tokens_factory: Callable | None = None,
            format: str | None = None,
        ) -> Any:
            """Convert a value to a python primitive type.

            Args:
                value: A primitive value or a list of primitive values
                types: An iterable of types to try to convert the value
                default: The default value/factory if the given is None
                ns_map: The element namespace prefix-URI map
                tokens_factory: A callable factory for the converted values
                    if the element is derived from xs:NMTOKENS
                format: The format argument for base64/hex values or dates.

            Returns:
                The converted value or values.
            """
            if value is None:
                if callable(default):
                    return default() if tokens_factory else None

                return default

            if tokens_factory:
                value = value if collections.is_array(value) else value.split()
                return tokens_factory(
                    converter.deserialize(val, types, ns_map=ns_map, format=format)
                    for val in value
                )

            return converter.deserialize(value, types, ns_map=ns_map, format=format)

        @classmethod
        def normalize_content(cls, value: str | None) -> str | None:
            """Normalize element text or tail content.

            If content is just whitespace return None, otherwise preserve
            the original content.

            Args:
                value: The element content

            Returns:
                The normalized content
            """
            if value and value.strip():
                return value

            return None

        @classmethod
        def parse_any_attributes(
            cls, attrs: dict[str, str], ns_map: dict[str | None, str]
        ) -> dict[str, str]:
            """Parse attributes with qname support.

            Example:
                {"foo": "bar", "xsi:type": "my:type"} ->
                {"foo": "bar", "xsi:type" "{http://someuri.com}type"}

            Args:
                attrs: The element attributes
                ns_map: The element namespace prefix-URI map

            Returns:
                The parsed attributes with expanded namespace prefixes
            """
            return {
                key: cls.parse_any_attribute(value, ns_map) for key, value in attrs.items()
            }

        @classmethod
        def parse_any_attribute(cls, value: str, ns_map: dict) -> str:
            """Expand the value with the full namespace if it has a prefix.

            Args:
                value: The attr value
                ns_map: The element namespace prefix-URI map

            Returns:
                The expanded value.
            """
            prefix, suffix = text.split(value)
            if prefix and prefix in ns_map and not suffix.startswith("//"):
                value = build_qname(ns_map[prefix], suffix)

            return value

        @classmethod
        def validate_fixed_value(cls, meta: XmlMeta, var: XmlVar, value: Any):
            """Validate if the parsed value matches the fixed value.

            Special cases
                - float nans are never equal in python
                - strings with whitespaces, need trimming
                - comparing raw str values
            """
            default_value = var.default() if callable(var.default) else var.default
            if (
                isinstance(default_value, float)
                and isinstance(value, float)
                and math.isnan(default_value)
                and math.isnan(value)
            ) or (
                isinstance(default_value, str)
                and isinstance(value, str)
                and default_value.strip() == value.strip()
            ):
                return

            if isinstance(value, str) and not isinstance(default_value, str):
                default_value = converter.serialize(default_value, format=var.format)

            if default_value != value:
                raise ParserError(
                    f"Fixed value mismatch {meta.qname}:{var.qname}, "
                    f"`{default_value} != {value}`"
                )

#### `xsi_type(attrs, ns_map)` `classmethod`

Parse the xsi:type attribute value if present.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`attrs` | `dict` | The element attributes | required
`ns_map` | `dict` | The element namespace prefix-URI map | required

Returns:

Type | Description
--- | ---
`str | None` | The xsi:type attribute value or None

Source code in `xsdata/formats/dataclass/parsers/utils.py`

    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69

    @classmethod
    def xsi_type(cls, attrs: dict, ns_map: dict) -> str | None:
        """Parse the xsi:type attribute value if present.

        Args:
            attrs: The element attributes
            ns_map: The element namespace prefix-URI map

        Returns:
            The xsi:type attribute value or None
        """
        xsi_type = attrs.get(QNames.XSI_TYPE)
        if not xsi_type:
            return None

        namespace, name = QNameConverter.resolve(xsi_type, ns_map)
        return build_qname(namespace, name)

#### `xsi_nil(attrs)` `classmethod`

Return whether xsi:nil attribute value.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`attrs` | `dict` | The element attributes | required

Returns:

Type | Description
--- | ---
`bool | None` | The bool value or None if it doesn't exist.

Source code in `xsdata/formats/dataclass/parsers/utils.py`

    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82

    @classmethod
    def xsi_nil(cls, attrs: dict) -> bool | None:
        """Return whether xsi:nil attribute value.

        Args:
            attrs: The element attributes

        Returns:
            The bool value or None if it doesn't exist.
        """
        xsi_nil = attrs.get(QNames.XSI_NIL)
        return xsi_nil == constants.XML_TRUE if xsi_nil else None

#### `parse_var(meta, var, config, value, ns_map=None, default=None, types=None, tokens_factory=None, format=None)` `classmethod`

Convert a value to a python primitive type.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`meta` | `XmlMeta` | The xml meta instance | required
`var` | `XmlVar` | The xml var instance | required
`config` | `ParserConfig` | The parser config instance | required
`value` | `Any` | A primitive value or a list of primitive values | required
`ns_map` | `dict | None` | The element namespace prefix-URI map | `None`
`default` | `Any` | Override the var default value | `None`
`types` | `Sequence[type] | None` | Override the var types | `None`
`tokens_factory` | `Callable | None` | Override the var tokens factory | `None`
`format` | `str | None` | Override the var format | `None`

Returns:

Type | Description
--- | ---
`Any` | The converted value or values.

Source code in `xsdata/formats/dataclass/parsers/utils.py`

     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132

    @classmethod
    def parse_var(
        cls,
        meta: XmlMeta,
        var: XmlVar,
        config: ParserConfig,
        value: Any,
        ns_map: dict | None = None,
        default: Any = None,
        types: Sequence[type] | None = None,
        tokens_factory: Callable | None = None,
        format: str | None = None,
    ) -> Any:
        """Convert a value to a python primitive type.

        Args:
            meta: The xml meta instance
            var: The xml var instance
            config: The parser config instance
            value: A primitive value or a list of primitive values
            ns_map: The element namespace prefix-URI map
            default: Override the var default value
            types: Override the var types
            tokens_factory: Override the var tokens factory
            format: Override the var format

        Returns:
            The converted value or values.
        """
        try:
            value = cls.parse_value(
                value=value,
                types=types or var.types,
                default=default or var.default,
                ns_map=ns_map,
                tokens_factory=tokens_factory or var.tokens_factory,
                format=format or var.format,
            )
        except ConverterError as ex:
            message = (
                "Failed to convert value for "
                f"`{meta.clazz.__qualname__}.{var.name}`\n  {ex}"
            )
            if config.fail_on_converter_warnings:
                raise ParserError(message)

            warnings.warn(message, ConverterWarning)

        return value

#### `parse_value(value, types, default=None, ns_map=None, tokens_factory=None, format=None)` `classmethod`

Convert a value to a python primitive type.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`value` | `Any` | A primitive value or a list of primitive values | required
`types` | `Sequence[type]` | An iterable of types to try to convert the value | required
`default` | `Any | None` | The default value/factory if the given is None | `None`
`ns_map` | `dict | None` | The element namespace prefix-URI map | `None`
`tokens_factory` | `Callable | None` | A callable factory for the converted values if the element is derived from xs:NMTOKENS | `None`
`format` | `str | None` | The format argument for base64/hex values or dates. | `None`

Returns:

Type | Description
--- | ---
`Any` | The converted value or values.

Source code in `xsdata/formats/dataclass/parsers/utils.py`

    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171

    @classmethod
    def parse_value(
        cls,
        value: Any,
        types: Sequence[type],
        default: Any | None = None,
        ns_map: dict | None = None,
        tokens_factory: Callable | None = None,
        format: str | None = None,
    ) -> Any:
        """Convert a value to a python primitive type.

        Args:
            value: A primitive value or a list of primitive values
            types: An iterable of types to try to convert the value
            default: The default value/factory if the given is None
            ns_map: The element namespace prefix-URI map
            tokens_factory: A callable factory for the converted values
                if the element is derived from xs:NMTOKENS
            format: The format argument for base64/hex values or dates.

        Returns:
            The converted value or values.
        """
        if value is None:
            if callable(default):
                return default() if tokens_factory else None

            return default

        if tokens_factory:
            value = value if collections.is_array(value) else value.split()
            return tokens_factory(
                converter.deserialize(val, types, ns_map=ns_map, format=format)
                for val in value
            )

        return converter.deserialize(value, types, ns_map=ns_map, format=format)

#### `normalize_content(value)` `classmethod`

Normalize element text or tail content.

If content is just whitespace return None, otherwise preserve the original content.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`value` | `str | None` | The element content | required

Returns:

Type | Description
--- | ---
`str | None` | The normalized content

Source code in `xsdata/formats/dataclass/parsers/utils.py`

    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189

    @classmethod
    def normalize_content(cls, value: str | None) -> str | None:
        """Normalize element text or tail content.

        If content is just whitespace return None, otherwise preserve
        the original content.

        Args:
            value: The element content

        Returns:
            The normalized content
        """
        if value and value.strip():
            return value

        return None

#### `parse_any_attributes(attrs, ns_map)` `classmethod`

Parse attributes with qname support.

Example

{"foo": "bar", "xsi:type": "my:type"} -> {"foo": "bar", "xsi:type" "{http://someuri.com}type"}

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`attrs` | `dict[str, str]` | The element attributes | required
`ns_map` | `dict[str | None, str]` | The element namespace prefix-URI map | required

Returns:

Type | Description
--- | ---
`dict[str, str]` | The parsed attributes with expanded namespace prefixes

Source code in `xsdata/formats/dataclass/parsers/utils.py`

    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210

    @classmethod
    def parse_any_attributes(
        cls, attrs: dict[str, str], ns_map: dict[str | None, str]
    ) -> dict[str, str]:
        """Parse attributes with qname support.

        Example:
            {"foo": "bar", "xsi:type": "my:type"} ->
            {"foo": "bar", "xsi:type" "{http://someuri.com}type"}

        Args:
            attrs: The element attributes
            ns_map: The element namespace prefix-URI map

        Returns:
            The parsed attributes with expanded namespace prefixes
        """
        return {
            key: cls.parse_any_attribute(value, ns_map) for key, value in attrs.items()
        }

#### `parse_any_attribute(value, ns_map)` `classmethod`

Expand the value with the full namespace if it has a prefix.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`value` | `str` | The attr value | required
`ns_map` | `dict` | The element namespace prefix-URI map | required

Returns:

Type | Description
--- | ---
`str` | The expanded value.

Source code in `xsdata/formats/dataclass/parsers/utils.py`

    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227

    @classmethod
    def parse_any_attribute(cls, value: str, ns_map: dict) -> str:
        """Expand the value with the full namespace if it has a prefix.

        Args:
            value: The attr value
            ns_map: The element namespace prefix-URI map

        Returns:
            The expanded value.
        """
        prefix, suffix = text.split(value)
        if prefix and prefix in ns_map and not suffix.startswith("//"):
            value = build_qname(ns_map[prefix], suffix)

        return value

#### `validate_fixed_value(meta, var, value)` `classmethod`

Validate if the parsed value matches the fixed value.

Special cases - float nans are never equal in python - strings with whitespaces, need trimming - comparing raw str values

Source code in `xsdata/formats/dataclass/parsers/utils.py`

    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258

    @classmethod
    def validate_fixed_value(cls, meta: XmlMeta, var: XmlVar, value: Any):
        """Validate if the parsed value matches the fixed value.

        Special cases
            - float nans are never equal in python
            - strings with whitespaces, need trimming
            - comparing raw str values
        """
        default_value = var.default() if callable(var.default) else var.default
        if (
            isinstance(default_value, float)
            and isinstance(value, float)
            and math.isnan(default_value)
            and math.isnan(value)
        ) or (
            isinstance(default_value, str)
            and isinstance(value, str)
            and default_value.strip() == value.strip()
        ):
            return

        if isinstance(value, str) and not isinstance(default_value, str):
            default_value = converter.serialize(default_value, format=var.format)

        if default_value != value:
            raise ParserError(
                f"Fixed value mismatch {meta.qname}:{var.qname}, "
                f"`{default_value} != {value}`"
            )