Skip to content

# bases

## `xsdata.formats.dataclass.parsers.bases`

### `NodeParser` `dataclass`

Bases: `PushParser`

Bind xml nodes to data classes.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`context` | `XmlContext` | The models context instance | `XmlContext()`
`handler` | `type[XmlHandler]` | The xml handler class | `EventsHandler`

Attributes:

Name | Type | Description
--- | --- | ---
`ns_map` | `dict[str | None, str]` | The parsed namespace prefix-URI map

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

     20
     21
     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
     48
     49
     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

    @dataclass
    class NodeParser(PushParser):
        """Bind xml nodes to data classes.

        Args:
            context: The models context instance
            handler: The xml handler class

        Attributes:
            ns_map: The parsed namespace prefix-URI map
        """

        context: XmlContext = field(default_factory=XmlContext)
        handler: type[XmlHandler] = field(default=EventsHandler)

        def parse(
            self,
            source: Any,
            clazz: type[T] | None = None,
            ns_map: dict[str | None, str] | None = None,
        ) -> T:
            """Parse the input file or stream into the target class type.

            If no clazz is provided, the binding context will try
            to locate it from imported dataclasses.

            Args:
                source: The source file or stream object to parse
                clazz: The target class type to parse the source bytes object
                ns_map: A namespace prefix-URI map to record prefixes during parsing

            Returns:
                An instance of the specified class representing the parsed content.
            """
            handler = self.handler(clazz=clazz, parser=self)

            try:
                ns_map = self.ns_map if ns_map is None else ns_map
                result = handler.parse(source, ns_map)
            except SyntaxError as e:
                raise ParserError(e)

            if result is not None:
                return result

            target_class = clazz.__name__ if clazz else ""
            raise ParserError(f"Failed to create target class `{target_class}`")

        def start(
            self,
            clazz: type | None,
            queue: list[XmlNode],
            objects: list[Parsed],
            qname: str,
            attrs: dict,
            ns_map: dict,
        ) -> None:
            """Build and queue the XmlNode for the starting element.

            Args:
                clazz: The target class type, auto locate if omitted
                queue: The XmlNode queue list
                objects: The list of all intermediate parsed objects
                qname: The element qualified name
                attrs: The element attributes
                ns_map: The element namespace prefix-URI map
            """
            from xsdata.formats.dataclass.parsers.nodes import ElementNode, WrapperNode

            try:
                item = queue[-1]
                if isinstance(item, ElementNode) and qname in item.meta.wrappers:
                    child = cast(XmlNode, WrapperNode(parent=item))
                else:
                    child = item.child(qname, attrs, ns_map, len(objects))
            except IndexError:
                xsi_type = ParserUtils.xsi_type(attrs, ns_map)

                clazz = self.find_root_clazz(
                    clazz=clazz,
                    qname=qname,
                    attrs=attrs,
                    ns_map=ns_map,
                    xsi_type=xsi_type,
                )
                # Exit if we still have no binding model
                if clazz is None:
                    raise ParserError(f"No class found matching root: {qname}")

                meta = self.context.fetch(clazz, xsi_type=xsi_type)
                if xsi_type is None or meta.qname == qname:
                    derived_factory = None
                else:
                    derived_factory = self.context.class_type.derived_element

                xsi_nil = ParserUtils.xsi_nil(attrs)

                child = ElementNode(
                    position=0,
                    meta=meta,
                    config=self.config,
                    attrs=attrs,
                    ns_map=ns_map,
                    context=self.context,
                    derived_factory=derived_factory,
                    xsi_type=xsi_type if derived_factory else None,
                    xsi_nil=xsi_nil,
                )

            queue.append(child)

        def end(
            self,
            queue: list[XmlNode],
            objects: list[Parsed],
            qname: str,
            text: str | None,
            tail: str | None,
        ) -> bool:
            """Parse the last xml node and bind any intermediate objects.

            Args:
                queue: The XmlNode queue list
                objects: The list of all intermediate parsed objects
                qname: The element qualified name
                text: The element text content
                tail: The element tail content

            Returns:
                Whether the binding process was successful.
            """
            item = queue.pop()
            return item.bind(qname, text, tail, objects)

        def find_root_clazz(
            self,
            clazz: type | None,
            qname: str,
            attrs: dict,
            ns_map: dict,
            xsi_type: str | None,
        ) -> type | None:
            """Obtain the root clazz, maybe from the provided clazz.

            Args:
                clazz: The root class type, auto locate if omitted
                qname: Qualified name
                attrs: Attribute key-value map
                ns_map: Namespace prefix-URI map
                xsi_type: The xsi:type of the object
            Returns:
                The root class.
            """
            # Match element qname directly
            if clazz is None:
                clazz = self.context.find_type(qname)

            # Root is xs:anyType try xsi:type
            if clazz is None and xsi_type:
                clazz = self.context.find_type(xsi_type)

            return clazz

#### `parse(source, clazz=None, ns_map=None)`

Parse the input file or stream into the target class type.

If no clazz is provided, the binding context will try to locate it from imported dataclasses.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`source` | `Any` | The source file or stream object to parse | required
`clazz` | `type[T] | None` | The target class type to parse the source bytes object | `None`
`ns_map` | `dict[str | None, str] | None` | A namespace prefix-URI map to record prefixes during parsing | `None`

Returns:

Type | Description
--- | ---
`T` | An instance of the specified class representing the parsed content.

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

    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66

    def parse(
        self,
        source: Any,
        clazz: type[T] | None = None,
        ns_map: dict[str | None, str] | None = None,
    ) -> T:
        """Parse the input file or stream into the target class type.

        If no clazz is provided, the binding context will try
        to locate it from imported dataclasses.

        Args:
            source: The source file or stream object to parse
            clazz: The target class type to parse the source bytes object
            ns_map: A namespace prefix-URI map to record prefixes during parsing

        Returns:
            An instance of the specified class representing the parsed content.
        """
        handler = self.handler(clazz=clazz, parser=self)

        try:
            ns_map = self.ns_map if ns_map is None else ns_map
            result = handler.parse(source, ns_map)
        except SyntaxError as e:
            raise ParserError(e)

        if result is not None:
            return result

        target_class = clazz.__name__ if clazz else ""
        raise ParserError(f"Failed to create target class `{target_class}`")

#### `start(clazz, queue, objects, qname, attrs, ns_map)`

Build and queue the XmlNode for the starting element.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`clazz` | `type | None` | The target class type, auto locate if omitted | required
`queue` | `list[XmlNode]` | The XmlNode queue list | required
`objects` | `list[Parsed]` | The list of all intermediate parsed objects | required
`qname` | `str` | The element qualified name | required
`attrs` | `dict` | The element attributes | required
`ns_map` | `dict` | The element namespace prefix-URI map | required

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

     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

    def start(
        self,
        clazz: type | None,
        queue: list[XmlNode],
        objects: list[Parsed],
        qname: str,
        attrs: dict,
        ns_map: dict,
    ) -> None:
        """Build and queue the XmlNode for the starting element.

        Args:
            clazz: The target class type, auto locate if omitted
            queue: The XmlNode queue list
            objects: The list of all intermediate parsed objects
            qname: The element qualified name
            attrs: The element attributes
            ns_map: The element namespace prefix-URI map
        """
        from xsdata.formats.dataclass.parsers.nodes import ElementNode, WrapperNode

        try:
            item = queue[-1]
            if isinstance(item, ElementNode) and qname in item.meta.wrappers:
                child = cast(XmlNode, WrapperNode(parent=item))
            else:
                child = item.child(qname, attrs, ns_map, len(objects))
        except IndexError:
            xsi_type = ParserUtils.xsi_type(attrs, ns_map)

            clazz = self.find_root_clazz(
                clazz=clazz,
                qname=qname,
                attrs=attrs,
                ns_map=ns_map,
                xsi_type=xsi_type,
            )
            # Exit if we still have no binding model
            if clazz is None:
                raise ParserError(f"No class found matching root: {qname}")

            meta = self.context.fetch(clazz, xsi_type=xsi_type)
            if xsi_type is None or meta.qname == qname:
                derived_factory = None
            else:
                derived_factory = self.context.class_type.derived_element

            xsi_nil = ParserUtils.xsi_nil(attrs)

            child = ElementNode(
                position=0,
                meta=meta,
                config=self.config,
                attrs=attrs,
                ns_map=ns_map,
                context=self.context,
                derived_factory=derived_factory,
                xsi_type=xsi_type if derived_factory else None,
                xsi_nil=xsi_nil,
            )

        queue.append(child)

#### `end(queue, objects, qname, text, tail)`

Parse the last xml node and bind any intermediate objects.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`queue` | `list[XmlNode]` | The XmlNode queue list | required
`objects` | `list[Parsed]` | The list of all intermediate parsed objects | required
`qname` | `str` | The element qualified name | required
`text` | `str | None` | The element text content | required
`tail` | `str | None` | The element tail content | required

Returns:

Type | Description
--- | ---
`bool` | Whether the binding process was successful.

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

    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152

    def end(
        self,
        queue: list[XmlNode],
        objects: list[Parsed],
        qname: str,
        text: str | None,
        tail: str | None,
    ) -> bool:
        """Parse the last xml node and bind any intermediate objects.

        Args:
            queue: The XmlNode queue list
            objects: The list of all intermediate parsed objects
            qname: The element qualified name
            text: The element text content
            tail: The element tail content

        Returns:
            Whether the binding process was successful.
        """
        item = queue.pop()
        return item.bind(qname, text, tail, objects)

#### `find_root_clazz(clazz, qname, attrs, ns_map, xsi_type)`

Obtain the root clazz, maybe from the provided clazz.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`clazz` | `type | None` | The root class type, auto locate if omitted | required
`qname` | `str` | Qualified name | required
`attrs` | `dict` | Attribute key-value map | required
`ns_map` | `dict` | Namespace prefix-URI map | required
`xsi_type` | `str | None` | The xsi:type of the object | required

Returns: The root class.

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

    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

    def find_root_clazz(
        self,
        clazz: type | None,
        qname: str,
        attrs: dict,
        ns_map: dict,
        xsi_type: str | None,
    ) -> type | None:
        """Obtain the root clazz, maybe from the provided clazz.

        Args:
            clazz: The root class type, auto locate if omitted
            qname: Qualified name
            attrs: Attribute key-value map
            ns_map: Namespace prefix-URI map
            xsi_type: The xsi:type of the object
        Returns:
            The root class.
        """
        # Match element qname directly
        if clazz is None:
            clazz = self.context.find_type(qname)

        # Root is xs:anyType try xsi:type
        if clazz is None and xsi_type:
            clazz = self.context.find_type(xsi_type)

        return clazz

### `RecordParser` `dataclass`

Bases: `NodeParser`

Bind xml nodes to dataclasses and store the intermediate events.

Attributes:

Name | Type | Description
--- | --- | ---
`events` | `list` | The list of recorded events

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

    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

    @dataclass
    class RecordParser(NodeParser):
        """Bind xml nodes to dataclasses and store the intermediate events.

        Attributes:
            events: The list of recorded events
        """

        events: list = field(init=False, default_factory=list)

        def start(
            self,
            clazz: type | None,
            queue: list[XmlNode],
            objects: list[Parsed],
            qname: str,
            attrs: dict,
            ns_map: dict,
        ) -> None:
            """Build and queue the XmlNode for the starting element.

            Record the start event for later processing.

            Args:
                clazz: The target class type, auto locate if omitted
                queue: The XmlNode queue list
                objects: The list of all intermediate parsed objects
                qname: The element qualified name
                attrs: The element attributes
                ns_map: The element namespace prefix-URI map
            """
            self.events.append((EventType.START, qname, copy.deepcopy(attrs), ns_map))
            super().start(clazz, queue, objects, qname, attrs, ns_map)

        def end(
            self,
            queue: list[XmlNode],
            objects: list[Parsed],
            qname: str,
            text: str | None,
            tail: str | None,
        ) -> Any:
            """Parse the last xml node and bind any intermediate objects.

            Record the end event for later processing

            Args:
                queue: The XmlNode queue list
                objects: The list of all intermediate parsed objects
                qname: The element qualified name
                text: The element text content
                tail: The element tail content

            Returns:
                Whether the binding process was successful.
            """
            self.events.append((EventType.END, qname, text, tail))
            return super().end(queue, objects, qname, text, tail)

        def register_namespace(
            self, ns_map: dict[str | None, str], prefix: str | None, uri: str
        ) -> None:
            """Register the uri prefix in the namespace prefix-URI map.

            Record the start-ns event for later processing.

            Args:
                ns_map: The namespace prefix-URI map
                prefix: The namespace prefix
                uri: The namespace uri
            """
            self.events.append((EventType.START_NS, prefix, uri))
            super().register_namespace(ns_map, prefix, uri)

#### `start(clazz, queue, objects, qname, attrs, ns_map)`

Build and queue the XmlNode for the starting element.

Record the start event for later processing.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`clazz` | `type | None` | The target class type, auto locate if omitted | required
`queue` | `list[XmlNode]` | The XmlNode queue list | required
`objects` | `list[Parsed]` | The list of all intermediate parsed objects | required
`qname` | `str` | The element qualified name | required
`attrs` | `dict` | The element attributes | required
`ns_map` | `dict` | The element namespace prefix-URI map | required

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

    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216

    def start(
        self,
        clazz: type | None,
        queue: list[XmlNode],
        objects: list[Parsed],
        qname: str,
        attrs: dict,
        ns_map: dict,
    ) -> None:
        """Build and queue the XmlNode for the starting element.

        Record the start event for later processing.

        Args:
            clazz: The target class type, auto locate if omitted
            queue: The XmlNode queue list
            objects: The list of all intermediate parsed objects
            qname: The element qualified name
            attrs: The element attributes
            ns_map: The element namespace prefix-URI map
        """
        self.events.append((EventType.START, qname, copy.deepcopy(attrs), ns_map))
        super().start(clazz, queue, objects, qname, attrs, ns_map)

#### `end(queue, objects, qname, text, tail)`

Parse the last xml node and bind any intermediate objects.

Record the end event for later processing

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`queue` | `list[XmlNode]` | The XmlNode queue list | required
`objects` | `list[Parsed]` | The list of all intermediate parsed objects | required
`qname` | `str` | The element qualified name | required
`text` | `str | None` | The element text content | required
`tail` | `str | None` | The element tail content | required

Returns:

Type | Description
--- | ---
`Any` | Whether the binding process was successful.

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

    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241

    def end(
        self,
        queue: list[XmlNode],
        objects: list[Parsed],
        qname: str,
        text: str | None,
        tail: str | None,
    ) -> Any:
        """Parse the last xml node and bind any intermediate objects.

        Record the end event for later processing

        Args:
            queue: The XmlNode queue list
            objects: The list of all intermediate parsed objects
            qname: The element qualified name
            text: The element text content
            tail: The element tail content

        Returns:
            Whether the binding process was successful.
        """
        self.events.append((EventType.END, qname, text, tail))
        return super().end(queue, objects, qname, text, tail)

#### `register_namespace(ns_map, prefix, uri)`

Register the uri prefix in the namespace prefix-URI map.

Record the start-ns event for later processing.

Parameters:

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

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

    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256

    def register_namespace(
        self, ns_map: dict[str | None, str], prefix: str | None, uri: str
    ) -> None:
        """Register the uri prefix in the namespace prefix-URI map.

        Record the start-ns event for later processing.

        Args:
            ns_map: The namespace prefix-URI map
            prefix: The namespace prefix
            uri: The namespace uri
        """
        self.events.append((EventType.START_NS, prefix, uri))
        super().register_namespace(ns_map, prefix, uri)