Skip to content

dtd

xsdata.codegen.mappers.dtd

DtdMapper

Maps a Dtd instance to a list of class instances.

Source code in xsdata/codegen/mappers/dtd.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
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
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
class DtdMapper:
    """Maps a Dtd instance to a list of class instances."""

    @classmethod
    def map(cls, dtd: Dtd) -> Iterator[Class]:
        """Map the given Dtd instance to a list of classes.

        Args:
            dtd: The Dtd instance to be mapped

        Yields:
            An iterator of mapped classes.
        """
        for element in dtd.elements:
            yield cls.build_class(element, dtd.location)

    @classmethod
    def build_class(cls, element: DtdElement, location: str) -> Class:
        """Build a class for the given element.

        Args:
            element: The dtd element to be mapped
            location: The location of dtd resource

        Returns:
            The mapped class instance.
        """
        target = Class(
            qname=element.qname,
            ns_map=element.ns_map,
            tag=Tag.ELEMENT,
            location=location,
        )

        cls.build_attributes(target, element)
        cls.build_elements(target, element)

        return target

    @classmethod
    def build_attributes(cls, target: Class, element: DtdElement):
        """Build attributes from the dtd element attributes.

        Args:
            target: The target class instance
            element: The dtd element containing attributes
        """
        for attribute in element.attributes:
            cls.build_attribute(target, attribute)

    @classmethod
    def build_attribute(cls, target: Class, attribute: DtdAttribute):
        """Build an attr from a dtd attribute.

        Args:
            target: The target class instance
            attribute: The dtd attribute to be mapped
        """
        attr_type = cls.build_attribute_type(target, attribute)
        attr = Attr(
            name=attribute.name,
            namespace=target.ns_map.get(attribute.prefix),
            tag=Tag.ATTRIBUTE,
            types=[attr_type],
        )

        cls.build_attribute_restrictions(
            attr, attribute.default, attribute.default_value
        )

        attr.index = len(target.attrs)
        target.attrs.append(attr)

    @classmethod
    def build_attribute_restrictions(
        cls,
        attr: Attr,
        default: DtdAttributeDefault,
        default_value: Optional[str],
    ):
        """Build attribute restrictions based on DtdAttributeDefault.

        Args:
            attr: The target attr instance
            default: The default attribute type
            default_value: The default value
        """
        attr.restrictions.max_occurs = 1
        if default == DtdAttributeDefault.REQUIRED:
            attr.restrictions.min_occurs = 1
        elif default == DtdAttributeDefault.IMPLIED:
            attr.restrictions.min_occurs = 0
        elif default == DtdAttributeDefault.FIXED:
            attr.fixed = True
            attr.restrictions.min_occurs = 1
            attr.default = default_value
        elif default_value is not None:
            attr.restrictions.min_occurs = 1
            attr.default = default_value
        else:
            attr.restrictions.min_occurs = 0

    @classmethod
    def build_attribute_type(cls, target: Class, attribute: DtdAttribute) -> AttrType:
        """Build attribute type based on the dtd attribute.

        Args:
            target: The target class instance
            attribute: The dtd attribute to be mapped

        Returns:
            The mapped attr type instance.
        """
        if attribute.type == DtdAttributeType.ENUMERATION:
            cls.build_enumeration(target, attribute.name, attribute.values)
            return AttrType(qname=attribute.name, forward=True)

        return AttrType(qname=str(attribute.data_type), native=True)

    @classmethod
    def build_elements(cls, target: Class, element: DtdElement):
        """Build attrs from the dtd element.

        Args:
            target: The target class instance
            element: The dtd containing elements.
        """
        if element.type == DtdElementType.ELEMENT and element.content:
            cls.build_content(target, element.content)
        elif element.type == DtdElementType.MIXED and element.content:
            cls.build_mixed_content(target, element.content)
        elif element.type == DtdElementType.ANY:
            cls.build_extension(target, DataType.ANY_TYPE)

    @classmethod
    def build_mixed_content(cls, target: Class, content: DtdContent):
        """Mark class to support mixed content.

        Args:
            target: The target class instance
            content: The dtd content instance
        """
        if content.left and content.left.type == DtdContentType.PCDATA:
            target.mixed = True
            content.left = None
        elif content.right and content.right.type == DtdContentType.PCDATA:
            target.mixed = True
            content.right = None

        target.tag = Tag.COMPLEX_TYPE
        cls.build_content(target, content)

    @classmethod
    def build_extension(cls, target: Class, data_type: DataType):
        """Add a xsd native type as class extension.

        Args:
            target: The target class instance
            data_type: The data type instance
        """
        ext_type = AttrType(qname=str(data_type), native=True)
        extension = Extension(
            tag=Tag.EXTENSION, type=ext_type, restrictions=Restrictions()
        )
        target.extensions.append(extension)

    @classmethod
    def build_content(cls, target: Class, content: DtdContent, **kwargs: Any):
        """Build class content.

        Args:
            target: The target class instance
            content: The dtd content instance.
            **kwargs: Additional restriction arguments.
        """
        content_type = content.type
        if content_type == DtdContentType.ELEMENT:
            restrictions = cls.build_restrictions(content.occur, **kwargs)
            cls.build_element(target, content.name, restrictions)
        elif content_type == DtdContentType.SEQ:
            cls.build_content_tree(target, content, **kwargs)
        elif content_type == DtdContentType.OR:
            params = cls.build_occurs(content.occur)
            params.update(
                {
                    "choice": id(content),
                    "min_occurs": 0,
                }
            )
            params.update(**kwargs)
            cls.build_content_tree(target, content, **params)
        else:  # content_type == DtdContentType.PCDATA:
            restrictions = cls.build_restrictions(content.occur, **kwargs)
            cls.build_value(target, restrictions)

    @classmethod
    def build_content_tree(cls, target: Class, content: DtdContent, **kwargs: Any):
        """Build the class content tree.

        Args:
            target: The target class instance
            content: The dtd content instance
            **kwargs: Additional restriction arguments
        """
        if content.left:
            cls.build_content(target, content.left, **kwargs)

        if content.right:
            cls.build_content(target, content.right, **kwargs)

    @classmethod
    def build_occurs(cls, occur: DtdContentOccur) -> Dict:
        """Calculate min/max occurs from the dtd content occur instance.

        Args:
            occur: The dtd content occur instance.

        Returns:
            The min/max occurs restrictions dictionary
        """
        if occur == DtdContentOccur.ONCE:
            min_occurs = 1
            max_occurs = 1
        elif occur == DtdContentOccur.OPT:
            min_occurs = 0
            max_occurs = 1
        elif occur == DtdContentOccur.MULT:
            min_occurs = 0
            max_occurs = sys.maxsize
        else:  # occur == DtdContentOccur.PLUS:
            min_occurs = 1
            max_occurs = sys.maxsize

        return {
            "min_occurs": min_occurs,
            "max_occurs": max_occurs,
        }

    @classmethod
    def build_restrictions(cls, occur: DtdContentOccur, **kwargs: Any) -> Restrictions:
        """Map the dtd content occur instance to a restriction instance.

        Args:
            occur: The DtdContentOccur to be mapped
            **kwargs: Additional restriction arguments

        Returns:
            The mapped restrictions instance.
        """
        params = cls.build_occurs(occur)
        params.update(kwargs)

        return Restrictions(**params)

    @classmethod
    def build_element(cls, target: Class, name: str, restrictions: Restrictions):
        """Build an element attr for the target class instance.

        Args:
            target: The target class instance
            name: The attr name
            restrictions: The attr restrictions
        """
        types = AttrType(qname=name, native=False)
        attr = Attr(
            name=name, tag=Tag.ELEMENT, types=[types], restrictions=restrictions.clone()
        )
        attr.index = len(target.attrs)
        target.attrs.append(attr)

    @classmethod
    def build_value(cls, target: Class, restrictions: Restrictions):
        """Build a value attr for the target class instance.

        Args:
            target: The target class instance
            restrictions: The attr restrictions
        """
        types = AttrType(qname=str(DataType.STRING), native=True)
        attr = Attr(
            name=DEFAULT_ATTR_NAME,
            tag=Tag.EXTENSION,
            types=[types],
            restrictions=restrictions.clone(),
        )
        attr.index = len(target.attrs)
        target.attrs.append(attr)

    @classmethod
    def build_enumeration(cls, target: Class, name: str, values: List[str]):
        """Build a nested enumeration class from the given values list.

        Args:
            target: The target class instance
            name: The attr/enum class name
            values: The enumeration values
        """
        inner = Class(qname=name, tag=Tag.SIMPLE_TYPE, location=target.location)
        attr_type = AttrType(qname=str(DataType.STRING), native=True)

        for value in values:
            inner.attrs.append(
                Attr(
                    fixed=True,
                    default=value,
                    name=value,
                    tag=Tag.ENUMERATION,
                    types=[attr_type.clone()],
                )
            )
        inner.parent = target
        target.inner.append(inner)

map(dtd) classmethod

Map the given Dtd instance to a list of classes.

Parameters:

Name Type Description Default
dtd Dtd

The Dtd instance to be mapped

required

Yields:

Type Description
Class

An iterator of mapped classes.

Source code in xsdata/codegen/mappers/dtd.py
23
24
25
26
27
28
29
30
31
32
33
34
@classmethod
def map(cls, dtd: Dtd) -> Iterator[Class]:
    """Map the given Dtd instance to a list of classes.

    Args:
        dtd: The Dtd instance to be mapped

    Yields:
        An iterator of mapped classes.
    """
    for element in dtd.elements:
        yield cls.build_class(element, dtd.location)

build_class(element, location) classmethod

Build a class for the given element.

Parameters:

Name Type Description Default
element DtdElement

The dtd element to be mapped

required
location str

The location of dtd resource

required

Returns:

Type Description
Class

The mapped class instance.

Source code in xsdata/codegen/mappers/dtd.py
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
@classmethod
def build_class(cls, element: DtdElement, location: str) -> Class:
    """Build a class for the given element.

    Args:
        element: The dtd element to be mapped
        location: The location of dtd resource

    Returns:
        The mapped class instance.
    """
    target = Class(
        qname=element.qname,
        ns_map=element.ns_map,
        tag=Tag.ELEMENT,
        location=location,
    )

    cls.build_attributes(target, element)
    cls.build_elements(target, element)

    return target

build_attributes(target, element) classmethod

Build attributes from the dtd element attributes.

Parameters:

Name Type Description Default
target Class

The target class instance

required
element DtdElement

The dtd element containing attributes

required
Source code in xsdata/codegen/mappers/dtd.py
59
60
61
62
63
64
65
66
67
68
@classmethod
def build_attributes(cls, target: Class, element: DtdElement):
    """Build attributes from the dtd element attributes.

    Args:
        target: The target class instance
        element: The dtd element containing attributes
    """
    for attribute in element.attributes:
        cls.build_attribute(target, attribute)

build_attribute(target, attribute) classmethod

Build an attr from a dtd attribute.

Parameters:

Name Type Description Default
target Class

The target class instance

required
attribute DtdAttribute

The dtd attribute to be mapped

required
Source code in xsdata/codegen/mappers/dtd.py
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
@classmethod
def build_attribute(cls, target: Class, attribute: DtdAttribute):
    """Build an attr from a dtd attribute.

    Args:
        target: The target class instance
        attribute: The dtd attribute to be mapped
    """
    attr_type = cls.build_attribute_type(target, attribute)
    attr = Attr(
        name=attribute.name,
        namespace=target.ns_map.get(attribute.prefix),
        tag=Tag.ATTRIBUTE,
        types=[attr_type],
    )

    cls.build_attribute_restrictions(
        attr, attribute.default, attribute.default_value
    )

    attr.index = len(target.attrs)
    target.attrs.append(attr)

build_attribute_restrictions(attr, default, default_value) classmethod

Build attribute restrictions based on DtdAttributeDefault.

Parameters:

Name Type Description Default
attr Attr

The target attr instance

required
default DtdAttributeDefault

The default attribute type

required
default_value Optional[str]

The default value

required
Source code in xsdata/codegen/mappers/dtd.py
 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
@classmethod
def build_attribute_restrictions(
    cls,
    attr: Attr,
    default: DtdAttributeDefault,
    default_value: Optional[str],
):
    """Build attribute restrictions based on DtdAttributeDefault.

    Args:
        attr: The target attr instance
        default: The default attribute type
        default_value: The default value
    """
    attr.restrictions.max_occurs = 1
    if default == DtdAttributeDefault.REQUIRED:
        attr.restrictions.min_occurs = 1
    elif default == DtdAttributeDefault.IMPLIED:
        attr.restrictions.min_occurs = 0
    elif default == DtdAttributeDefault.FIXED:
        attr.fixed = True
        attr.restrictions.min_occurs = 1
        attr.default = default_value
    elif default_value is not None:
        attr.restrictions.min_occurs = 1
        attr.default = default_value
    else:
        attr.restrictions.min_occurs = 0

build_attribute_type(target, attribute) classmethod

Build attribute type based on the dtd attribute.

Parameters:

Name Type Description Default
target Class

The target class instance

required
attribute DtdAttribute

The dtd attribute to be mapped

required

Returns:

Type Description
AttrType

The mapped attr type instance.

Source code in xsdata/codegen/mappers/dtd.py
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
@classmethod
def build_attribute_type(cls, target: Class, attribute: DtdAttribute) -> AttrType:
    """Build attribute type based on the dtd attribute.

    Args:
        target: The target class instance
        attribute: The dtd attribute to be mapped

    Returns:
        The mapped attr type instance.
    """
    if attribute.type == DtdAttributeType.ENUMERATION:
        cls.build_enumeration(target, attribute.name, attribute.values)
        return AttrType(qname=attribute.name, forward=True)

    return AttrType(qname=str(attribute.data_type), native=True)

build_elements(target, element) classmethod

Build attrs from the dtd element.

Parameters:

Name Type Description Default
target Class

The target class instance

required
element DtdElement

The dtd containing elements.

required
Source code in xsdata/codegen/mappers/dtd.py
139
140
141
142
143
144
145
146
147
148
149
150
151
152
@classmethod
def build_elements(cls, target: Class, element: DtdElement):
    """Build attrs from the dtd element.

    Args:
        target: The target class instance
        element: The dtd containing elements.
    """
    if element.type == DtdElementType.ELEMENT and element.content:
        cls.build_content(target, element.content)
    elif element.type == DtdElementType.MIXED and element.content:
        cls.build_mixed_content(target, element.content)
    elif element.type == DtdElementType.ANY:
        cls.build_extension(target, DataType.ANY_TYPE)

build_mixed_content(target, content) classmethod

Mark class to support mixed content.

Parameters:

Name Type Description Default
target Class

The target class instance

required
content DtdContent

The dtd content instance

required
Source code in xsdata/codegen/mappers/dtd.py
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
@classmethod
def build_mixed_content(cls, target: Class, content: DtdContent):
    """Mark class to support mixed content.

    Args:
        target: The target class instance
        content: The dtd content instance
    """
    if content.left and content.left.type == DtdContentType.PCDATA:
        target.mixed = True
        content.left = None
    elif content.right and content.right.type == DtdContentType.PCDATA:
        target.mixed = True
        content.right = None

    target.tag = Tag.COMPLEX_TYPE
    cls.build_content(target, content)

build_extension(target, data_type) classmethod

Add a xsd native type as class extension.

Parameters:

Name Type Description Default
target Class

The target class instance

required
data_type DataType

The data type instance

required
Source code in xsdata/codegen/mappers/dtd.py
172
173
174
175
176
177
178
179
180
181
182
183
184
@classmethod
def build_extension(cls, target: Class, data_type: DataType):
    """Add a xsd native type as class extension.

    Args:
        target: The target class instance
        data_type: The data type instance
    """
    ext_type = AttrType(qname=str(data_type), native=True)
    extension = Extension(
        tag=Tag.EXTENSION, type=ext_type, restrictions=Restrictions()
    )
    target.extensions.append(extension)

build_content(target, content, **kwargs) classmethod

Build class content.

Parameters:

Name Type Description Default
target Class

The target class instance

required
content DtdContent

The dtd content instance.

required
**kwargs Any

Additional restriction arguments.

{}
Source code in xsdata/codegen/mappers/dtd.py
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
@classmethod
def build_content(cls, target: Class, content: DtdContent, **kwargs: Any):
    """Build class content.

    Args:
        target: The target class instance
        content: The dtd content instance.
        **kwargs: Additional restriction arguments.
    """
    content_type = content.type
    if content_type == DtdContentType.ELEMENT:
        restrictions = cls.build_restrictions(content.occur, **kwargs)
        cls.build_element(target, content.name, restrictions)
    elif content_type == DtdContentType.SEQ:
        cls.build_content_tree(target, content, **kwargs)
    elif content_type == DtdContentType.OR:
        params = cls.build_occurs(content.occur)
        params.update(
            {
                "choice": id(content),
                "min_occurs": 0,
            }
        )
        params.update(**kwargs)
        cls.build_content_tree(target, content, **params)
    else:  # content_type == DtdContentType.PCDATA:
        restrictions = cls.build_restrictions(content.occur, **kwargs)
        cls.build_value(target, restrictions)

build_content_tree(target, content, **kwargs) classmethod

Build the class content tree.

Parameters:

Name Type Description Default
target Class

The target class instance

required
content DtdContent

The dtd content instance

required
**kwargs Any

Additional restriction arguments

{}
Source code in xsdata/codegen/mappers/dtd.py
215
216
217
218
219
220
221
222
223
224
225
226
227
228
@classmethod
def build_content_tree(cls, target: Class, content: DtdContent, **kwargs: Any):
    """Build the class content tree.

    Args:
        target: The target class instance
        content: The dtd content instance
        **kwargs: Additional restriction arguments
    """
    if content.left:
        cls.build_content(target, content.left, **kwargs)

    if content.right:
        cls.build_content(target, content.right, **kwargs)

build_occurs(occur) classmethod

Calculate min/max occurs from the dtd content occur instance.

Parameters:

Name Type Description Default
occur DtdContentOccur

The dtd content occur instance.

required

Returns:

Type Description
Dict

The min/max occurs restrictions dictionary

Source code in xsdata/codegen/mappers/dtd.py
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
@classmethod
def build_occurs(cls, occur: DtdContentOccur) -> Dict:
    """Calculate min/max occurs from the dtd content occur instance.

    Args:
        occur: The dtd content occur instance.

    Returns:
        The min/max occurs restrictions dictionary
    """
    if occur == DtdContentOccur.ONCE:
        min_occurs = 1
        max_occurs = 1
    elif occur == DtdContentOccur.OPT:
        min_occurs = 0
        max_occurs = 1
    elif occur == DtdContentOccur.MULT:
        min_occurs = 0
        max_occurs = sys.maxsize
    else:  # occur == DtdContentOccur.PLUS:
        min_occurs = 1
        max_occurs = sys.maxsize

    return {
        "min_occurs": min_occurs,
        "max_occurs": max_occurs,
    }

build_restrictions(occur, **kwargs) classmethod

Map the dtd content occur instance to a restriction instance.

Parameters:

Name Type Description Default
occur DtdContentOccur

The DtdContentOccur to be mapped

required
**kwargs Any

Additional restriction arguments

{}

Returns:

Type Description
Restrictions

The mapped restrictions instance.

Source code in xsdata/codegen/mappers/dtd.py
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
@classmethod
def build_restrictions(cls, occur: DtdContentOccur, **kwargs: Any) -> Restrictions:
    """Map the dtd content occur instance to a restriction instance.

    Args:
        occur: The DtdContentOccur to be mapped
        **kwargs: Additional restriction arguments

    Returns:
        The mapped restrictions instance.
    """
    params = cls.build_occurs(occur)
    params.update(kwargs)

    return Restrictions(**params)

build_element(target, name, restrictions) classmethod

Build an element attr for the target class instance.

Parameters:

Name Type Description Default
target Class

The target class instance

required
name str

The attr name

required
restrictions Restrictions

The attr restrictions

required
Source code in xsdata/codegen/mappers/dtd.py
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
@classmethod
def build_element(cls, target: Class, name: str, restrictions: Restrictions):
    """Build an element attr for the target class instance.

    Args:
        target: The target class instance
        name: The attr name
        restrictions: The attr restrictions
    """
    types = AttrType(qname=name, native=False)
    attr = Attr(
        name=name, tag=Tag.ELEMENT, types=[types], restrictions=restrictions.clone()
    )
    attr.index = len(target.attrs)
    target.attrs.append(attr)

build_value(target, restrictions) classmethod

Build a value attr for the target class instance.

Parameters:

Name Type Description Default
target Class

The target class instance

required
restrictions Restrictions

The attr restrictions

required
Source code in xsdata/codegen/mappers/dtd.py
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
@classmethod
def build_value(cls, target: Class, restrictions: Restrictions):
    """Build a value attr for the target class instance.

    Args:
        target: The target class instance
        restrictions: The attr restrictions
    """
    types = AttrType(qname=str(DataType.STRING), native=True)
    attr = Attr(
        name=DEFAULT_ATTR_NAME,
        tag=Tag.EXTENSION,
        types=[types],
        restrictions=restrictions.clone(),
    )
    attr.index = len(target.attrs)
    target.attrs.append(attr)

build_enumeration(target, name, values) classmethod

Build a nested enumeration class from the given values list.

Parameters:

Name Type Description Default
target Class

The target class instance

required
name str

The attr/enum class name

required
values List[str]

The enumeration values

required
Source code in xsdata/codegen/mappers/dtd.py
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
@classmethod
def build_enumeration(cls, target: Class, name: str, values: List[str]):
    """Build a nested enumeration class from the given values list.

    Args:
        target: The target class instance
        name: The attr/enum class name
        values: The enumeration values
    """
    inner = Class(qname=name, tag=Tag.SIMPLE_TYPE, location=target.location)
    attr_type = AttrType(qname=str(DataType.STRING), native=True)

    for value in values:
        inner.attrs.append(
            Attr(
                fixed=True,
                default=value,
                name=value,
                tag=Tag.ENUMERATION,
                types=[attr_type.clone()],
            )
        )
    inner.parent = target
    target.inner.append(inner)