Skip to content

# element

## `xsdata.codegen.mappers.element`

### `ElementMapper`

Bases: `RawDocumentMapper`

Map a generic element to classes.

This mapper is used to build classes from raw xml documents.

Source code in `xsdata/codegen/mappers/element.py`

     12
     13
     14
     15
     16
     17
     18
     19
     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

    class ElementMapper(RawDocumentMapper):
        """Map a generic element to classes.

        This mapper is used to build classes from raw xml documents.
        """

        @classmethod
        def map(cls, element: AnyElement, location: str) -> list[Class]:
            """Map schema children elements to classes.

            Args:
                element: The root element to be mapped
                location: The location of the xml document

            Returns:
                The list of mapped class instances.
            """
            assert element.qname is not None

            uri, name = split_qname(element.qname)
            target = cls.build_class(element, uri)

            return list(ClassUtils.flatten(target, f"{location}/{name}"))

        @classmethod
        def build_class(cls, element: AnyElement, parent_namespace: str | None) -> Class:
            """Build a Class instance for the given generic element.

            Args:
                element: The generic element to be mapped
                parent_namespace: The parent element namespace

            Returns:
                The mapped class instance.
            """
            assert element.qname is not None

            namespace, name = split_qname(element.qname)
            namespace = cls.select_namespace(namespace, parent_namespace)
            target = Class(
                qname=build_qname(namespace, name),
                namespace=namespace,
                tag=Tag.ELEMENT,
                location="",
            )

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

            return target

        @classmethod
        def build_attributes(
            cls,
            target: Class,
            element: AnyElement,
            namespace: str | None,
        ):
            """Build attributes for the given Class instance based on AnyElement attributes.

            Args:
                target: The target class instance
                element: The AnyElement containing attributes.
                namespace: The namespace.

            """
            for key, value in element.attributes.items():
                if key == QNames.XSI_NIL:
                    target.nillable = value.strip() in ("true", "1")
                else:
                    attr_type = cls.build_attr_type(key, value)
                    cls.build_attr(target, key, attr_type, namespace, Tag.ATTRIBUTE)

        @classmethod
        def build_elements(
            cls,
            target: Class,
            element: AnyElement,
            namespace: str | None,
        ):
            """Build elements for the given Class instance based on AnyElement children.

            Args:
                target: The target class instance
                element: The AnyElement containing children.
                namespace: The namespace.
            """
            sequences = cls.sequential_groups(element)
            for index, child in enumerate(element.children):
                if isinstance(child, AnyElement) and child.qname:
                    if child.tail:
                        target.mixed = True

                    if child.attributes or child.children:
                        inner = cls.build_class(child, namespace)
                        inner.parent = target
                        attr_type = AttrType(qname=inner.qname, forward=True)
                        target.inner.append(inner)
                    else:
                        attr_type = cls.build_attr_type(child.qname, child.text)

                    sequence = collections.find_connected_component(sequences, index)
                    cls.build_attr(
                        target,
                        child.qname,
                        attr_type,
                        namespace,
                        Tag.ELEMENT,
                        sequence + 1,
                    )

        @classmethod
        def build_text(cls, target: Class, element: AnyElement):
            """Build a text attr from the generic element text value.

            Args:
                target: The target class instance
                element: The AnyElement containing text content.
            """
            if element.text:
                attr_type = cls.build_attr_type("value", element.text)
                cls.build_attr(target, "value", attr_type, None, Tag.SIMPLE_TYPE)

                if any(attr.tag == Tag.ELEMENT for attr in target.attrs):
                    target.mixed = True

        @classmethod
        def sequential_groups(cls, element: AnyElement) -> list[list[int]]:
            """Identify sequential groups of repeating attributes.

            Args:
                element: The generic element instance

            Returns:
                A list of lists of strongly connected children indexes.
            """
            groups = cls.group_repeating_attrs(element)
            return list(collections.connected_components(groups))

        @classmethod
        def group_repeating_attrs(cls, element: AnyElement) -> list[list[int]]:
            """Group repeating children in the given generic element.

            Args:
                element: The generic element instance

            Returns:
                A list of lists of children indexes.
            """
            counters = defaultdict(list)
            for index, child in enumerate(element.children):
                if isinstance(child, AnyElement) and child.qname:
                    counters[child.qname].append(index)

            groups: list[list[int]] = []
            if len(counters) > 1:
                groups.extend(
                    list(range(x[0], x[-1] + 1)) for x in counters.values() if len(x) > 1
                )
            return groups

#### `map(element, location)` `classmethod`

Map schema children elements to classes.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`element` | `AnyElement` | The root element to be mapped | required
`location` | `str` | The location of the xml document | required

Returns:

Type | Description
--- | ---
`list[Class]` | The list of mapped class instances.

Source code in `xsdata/codegen/mappers/element.py`

    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34

    @classmethod
    def map(cls, element: AnyElement, location: str) -> list[Class]:
        """Map schema children elements to classes.

        Args:
            element: The root element to be mapped
            location: The location of the xml document

        Returns:
            The list of mapped class instances.
        """
        assert element.qname is not None

        uri, name = split_qname(element.qname)
        target = cls.build_class(element, uri)

        return list(ClassUtils.flatten(target, f"{location}/{name}"))

#### `build_class(element, parent_namespace)` `classmethod`

Build a Class instance for the given generic element.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`element` | `AnyElement` | The generic element to be mapped | required
`parent_namespace` | `str | None` | The parent element namespace | required

Returns:

Type | Description
--- | ---
`Class` | The mapped class instance.

Source code in `xsdata/codegen/mappers/element.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

    @classmethod
    def build_class(cls, element: AnyElement, parent_namespace: str | None) -> Class:
        """Build a Class instance for the given generic element.

        Args:
            element: The generic element to be mapped
            parent_namespace: The parent element namespace

        Returns:
            The mapped class instance.
        """
        assert element.qname is not None

        namespace, name = split_qname(element.qname)
        namespace = cls.select_namespace(namespace, parent_namespace)
        target = Class(
            qname=build_qname(namespace, name),
            namespace=namespace,
            tag=Tag.ELEMENT,
            location="",
        )

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

        return target

#### `build_attributes(target, element, namespace)` `classmethod`

Build attributes for the given Class instance based on AnyElement attributes.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`target` | `Class` | The target class instance | required
`element` | `AnyElement` | The AnyElement containing attributes. | required
`namespace` | `str | None` | The namespace. | required

Source code in `xsdata/codegen/mappers/element.py`

    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84

    @classmethod
    def build_attributes(
        cls,
        target: Class,
        element: AnyElement,
        namespace: str | None,
    ):
        """Build attributes for the given Class instance based on AnyElement attributes.

        Args:
            target: The target class instance
            element: The AnyElement containing attributes.
            namespace: The namespace.

        """
        for key, value in element.attributes.items():
            if key == QNames.XSI_NIL:
                target.nillable = value.strip() in ("true", "1")
            else:
                attr_type = cls.build_attr_type(key, value)
                cls.build_attr(target, key, attr_type, namespace, Tag.ATTRIBUTE)

#### `build_elements(target, element, namespace)` `classmethod`

Build elements for the given Class instance based on AnyElement children.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`target` | `Class` | The target class instance | required
`element` | `AnyElement` | The AnyElement containing children. | required
`namespace` | `str | None` | The namespace. | required

Source code in `xsdata/codegen/mappers/element.py`

     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

    @classmethod
    def build_elements(
        cls,
        target: Class,
        element: AnyElement,
        namespace: str | None,
    ):
        """Build elements for the given Class instance based on AnyElement children.

        Args:
            target: The target class instance
            element: The AnyElement containing children.
            namespace: The namespace.
        """
        sequences = cls.sequential_groups(element)
        for index, child in enumerate(element.children):
            if isinstance(child, AnyElement) and child.qname:
                if child.tail:
                    target.mixed = True

                if child.attributes or child.children:
                    inner = cls.build_class(child, namespace)
                    inner.parent = target
                    attr_type = AttrType(qname=inner.qname, forward=True)
                    target.inner.append(inner)
                else:
                    attr_type = cls.build_attr_type(child.qname, child.text)

                sequence = collections.find_connected_component(sequences, index)
                cls.build_attr(
                    target,
                    child.qname,
                    attr_type,
                    namespace,
                    Tag.ELEMENT,
                    sequence + 1,
                )

#### `build_text(target, element)` `classmethod`

Build a text attr from the generic element text value.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`target` | `Class` | The target class instance | required
`element` | `AnyElement` | The AnyElement containing text content. | required

Source code in `xsdata/codegen/mappers/element.py`

    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137

    @classmethod
    def build_text(cls, target: Class, element: AnyElement):
        """Build a text attr from the generic element text value.

        Args:
            target: The target class instance
            element: The AnyElement containing text content.
        """
        if element.text:
            attr_type = cls.build_attr_type("value", element.text)
            cls.build_attr(target, "value", attr_type, None, Tag.SIMPLE_TYPE)

            if any(attr.tag == Tag.ELEMENT for attr in target.attrs):
                target.mixed = True

#### `sequential_groups(element)` `classmethod`

Identify sequential groups of repeating attributes.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`element` | `AnyElement` | The generic element instance | required

Returns:

Type | Description
--- | ---
`list[list[int]]` | A list of lists of strongly connected children indexes.

Source code in `xsdata/codegen/mappers/element.py`

    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150

    @classmethod
    def sequential_groups(cls, element: AnyElement) -> list[list[int]]:
        """Identify sequential groups of repeating attributes.

        Args:
            element: The generic element instance

        Returns:
            A list of lists of strongly connected children indexes.
        """
        groups = cls.group_repeating_attrs(element)
        return list(collections.connected_components(groups))

#### `group_repeating_attrs(element)` `classmethod`

Group repeating children in the given generic element.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`element` | `AnyElement` | The generic element instance | required

Returns:

Type | Description
--- | ---
`list[list[int]]` | A list of lists of children indexes.

Source code in `xsdata/codegen/mappers/element.py`

    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172

    @classmethod
    def group_repeating_attrs(cls, element: AnyElement) -> list[list[int]]:
        """Group repeating children in the given generic element.

        Args:
            element: The generic element instance

        Returns:
            A list of lists of children indexes.
        """
        counters = defaultdict(list)
        for index, child in enumerate(element.children):
            if isinstance(child, AnyElement) and child.qname:
                counters[child.qname].append(index)

        groups: list[list[int]] = []
        if len(counters) > 1:
            groups.extend(
                list(range(x[0], x[-1] + 1)) for x in counters.values() if len(x) > 1
            )
        return groups