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

The parsed namespace prefix-URI map

Source code in xsdata/formats/dataclass/parsers/bases.py
 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
@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: Optional[Type[T]] = None,
        ns_map: Optional[Dict[Optional[str], str]] = 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)

        with warnings.catch_warnings():
            if self.config.fail_on_converter_warnings:
                warnings.filterwarnings("error", category=ConverterWarning)

            try:
                ns_map = self.ns_map if ns_map is None else ns_map
                result = handler.parse(source, ns_map)
            except (ConverterWarning, 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: Optional[Type],
        queue: List[XmlNode],
        objects: List[Parsed],
        qname: str,
        attrs: Dict,
        ns_map: Dict,
    ):
        """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)

            # 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)

            # 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: Optional[str],
        tail: Optional[str],
    ) -> 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)

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 Optional[Type[T]]

The target class type to parse the source bytes object

None
ns_map Optional[Dict[Optional[str], str]]

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
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
def parse(
    self,
    source: Any,
    clazz: Optional[Type[T]] = None,
    ns_map: Optional[Dict[Optional[str], str]] = 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)

    with warnings.catch_warnings():
        if self.config.fail_on_converter_warnings:
            warnings.filterwarnings("error", category=ConverterWarning)

        try:
            ns_map = self.ns_map if ns_map is None else ns_map
            result = handler.parse(source, ns_map)
        except (ConverterWarning, 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 Optional[Type]

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
 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
def start(
    self,
    clazz: Optional[Type],
    queue: List[XmlNode],
    objects: List[Parsed],
    qname: str,
    attrs: Dict,
    ns_map: Dict,
):
    """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)

        # 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)

        # 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 Optional[str]

The element text content

required
tail Optional[str]

The element tail content

required

Returns:

Type Description
bool

Whether the binding process was successful.

Source code in xsdata/formats/dataclass/parsers/bases.py
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
def end(
    self,
    queue: List[XmlNode],
    objects: List[Parsed],
    qname: str,
    text: Optional[str],
    tail: Optional[str],
) -> 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)

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
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
@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: Optional[Type],
        queue: List[XmlNode],
        objects: List[Parsed],
        qname: str,
        attrs: Dict,
        ns_map: Dict,
    ):
        """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: Optional[str],
        tail: Optional[str],
    ) -> 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[Optional[str], str], prefix: Optional[str], uri: str
    ):
        """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 Optional[Type]

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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
def start(
    self,
    clazz: Optional[Type],
    queue: List[XmlNode],
    objects: List[Parsed],
    qname: str,
    attrs: Dict,
    ns_map: Dict,
):
    """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 Optional[str]

The element text content

required
tail Optional[str]

The element tail content

required

Returns:

Type Description
Any

Whether the binding process was successful.

Source code in xsdata/formats/dataclass/parsers/bases.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
def end(
    self,
    queue: List[XmlNode],
    objects: List[Parsed],
    qname: str,
    text: Optional[str],
    tail: Optional[str],
) -> 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[Optional[str], str]

The namespace prefix-URI map

required
prefix Optional[str]

The namespace prefix

required
uri str

The namespace uri

required
Source code in xsdata/formats/dataclass/parsers/bases.py
220
221
222
223
224
225
226
227
228
229
230
231
232
233
def register_namespace(
    self, ns_map: Dict[Optional[str], str], prefix: Optional[str], uri: str
):
    """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)