Repository: tefra/xsdata

Issue:
XML schema-derived Enumerator and Pattern have prohibited "fixed" attribute
Hi! I'm successfully using this great library to generate code from some BIM related XSD files, namely [BCF XML](https://github.com/buildingSMART/BCF-XML/tree/release_3_0/Schemas) and [IDS XML](https://github.com/buildingSMART/IDS/blob/master/Development/ids.xsd) specifications.

I've stumbled upon a problem with the latter: XML files created using the generated classes are invalid, because the `xs:enumeration` and `xs:pattern` elements have a `fixed="false"` attribute that is not allowed.

To generate the classes, I used the command

```
xsdata generate -p ids.model -ds Google --kw-only --slots ./ids.xsd
```

At the beginning of the file there are some namespace imports:

```
<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
<xs:import namespace="http://www.w3.org/2001/XMLSchema" schemaLocation="https://www.w3.org/2001/XMLSchema.xsd"/>
<xs:import namespace="http://www.w3.org/2001/XMLSchema-instance" schemaLocation="http://www.w3.org/2001/XMLSchema-instance"/>
```

So xsdata generates the three modules: `ids.xml`. `xmlschema.py` and `xml.py`.

The `enumeration` element has `noFixedFacet` type

```xml
<xs:element name="enumeration" id="enumeration" type="xs:noFixedFacet">
  <xs:annotation>
    <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-enumeration"/>
  </xs:annotation>
</xs:element>
```

and is translated as

```py
@dataclass(slots=True, kw_only=True)
class Enumeration(NoFixedFacet):
    class Meta:
        name = "enumeration"
        namespace = "http://www.w3.org/2001/XMLSchema"
```

`noFixedFaced` is based on `facet`, but prohibits the use of the `fixed` attribute defined in the `facet`:

```xml
<xs:complexType name="facet">
  <xs:complexContent>
    <xs:extension base="xs:annotated">
      <xs:attribute name="value" use="required"/>
      <xs:attribute name="fixed" type="xs:boolean" use="optional" default="false"/>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>
<xs:complexType name="noFixedFacet">
  <xs:complexContent>
    <xs:restriction base="xs:facet">
      <xs:sequence>
        <xs:element ref="xs:annotation" minOccurs="0"/>
      </xs:sequence>
      <xs:attribute name="fixed" use="prohibited"/>
      <xs:anyAttribute namespace="##other" processContents="lax"/>
    </xs:restriction>
  </xs:complexContent>
</xs:complexType>
```

But this results in an empty `NoFixedFacet` dataclass that inherits from the `Facet` class, and it doesn't remove the `fixed` attibute:

```py
@dataclass(slots=True, kw_only=True)
class Facet(Annotated):
    class Meta:
        name = "facet"

    value: str = field(
        metadata={
            "type": "Attribute",
            "required": True,
        }
    )
    fixed: bool = field(
        default=False,
        metadata={
            "type": "Attribute",
        }
    )


@dataclass(slots=True, kw_only=True)
class NoFixedFacet(Facet):
    class Meta:
        name = "noFixedFacet"
```

I can fix this by manually editing the `NoFixedFaced` without inheriting form `Facet`, but is there a way to tell xsdata to handle the `prohibited` use of the `fixed` attribute (so that I don't have to worry about schema updates in the future)?

Discussion:
sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=790)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=790&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=790&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=790&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=790) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=790&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=790&metric=new_duplicated_lines_density&view=list)


tefra: Unfortunately this revealed a naming conflict with the reserved words :facepalm: 
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/tefra/xsdata/pull/790?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) Report
Patch coverage: **`100.00`**% and no project coverage change.
> Comparison is base [(`ad3628e`)](https://app.codecov.io/gh/tefra/xsdata/commit/ad3628e56056fd06475393faefb093be6bb7bb67?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) 99.96% compared to head [(`3dd0c86`)](https://app.codecov.io/gh/tefra/xsdata/pull/790?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) 99.96%.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##           master     #790   +/-   ##
=======================================
  Coverage   99.96%   99.96%           
=======================================
  Files         104      104           
  Lines        9125     9133    +8     
  Branches     2042     2045    +3     
=======================================
+ Hits         9122     9130    +8     
  Partials        3        3           
```


| [Impacted Files](https://app.codecov.io/gh/tefra/xsdata/pull/790?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) | Coverage Δ | |
|---|---|---|
| [xsdata/codegen/mappers/schema.py](https://app.codecov.io/gh/tefra/xsdata/pull/790?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou#diff-eHNkYXRhL2NvZGVnZW4vbWFwcGVycy9zY2hlbWEucHk=) | `100.00% <ø> (ø)` | |
| [xsdata/utils/text.py](https://app.codecov.io/gh/tefra/xsdata/pull/790?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou#diff-eHNkYXRhL3V0aWxzL3RleHQucHk=) | `100.00% <ø> (ø)` | |
| [.../codegen/handlers/validate\_attributes\_overrides.py](https://app.codecov.io/gh/tefra/xsdata/pull/790?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou#diff-eHNkYXRhL2NvZGVnZW4vaGFuZGxlcnMvdmFsaWRhdGVfYXR0cmlidXRlc19vdmVycmlkZXMucHk=) | `100.00% <100.00%> (ø)` | |
| [xsdata/codegen/models.py](https://app.codecov.io/gh/tefra/xsdata/pull/790?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou#diff-eHNkYXRhL2NvZGVnZW4vbW9kZWxzLnB5) | `100.00% <100.00%> (ø)` | |
| [xsdata/formats/dataclass/filters.py](https://app.codecov.io/gh/tefra/xsdata/pull/790?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou#diff-eHNkYXRhL2Zvcm1hdHMvZGF0YWNsYXNzL2ZpbHRlcnMucHk=) | `99.72% <100.00%> (+<0.01%)` | :arrow_up: |


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/tefra/xsdata/pull/790?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).

rvalyi: > Unfortunately this revealed a naming conflict with the reserved words facepalm

Hello @tefra I'm just taking the opportunity to mention that when using the originalCase option (IMHO the best option to stick to the XML attrs everybody will know), you can easily have an field that is named like a tag and have conflicts a bit similar to reserved words but with dataclass names this time. Often I had such cases for the Brazilian invoicing and often I could deal with it by adding a substitution lower casing the 1st field name letter. For instance https://github.com/akretion/nfelib/blob/master-xsdata/.xsdata.xml#L35 but eventually you have a better idea to fix it in the code. Do you think it's worth creating an issue for it?
tefra: > > Unfortunately this revealed a naming conflict with the reserved words facepalm
> 
> Hello @tefra I'm just taking the opportunity to mention that when using the originalCase option (IMHO the best option to stick to the XML attrs everybody will know), you can easily have an field that is named like a tag and have conflicts a bit similar to reserved words but with dataclass names this time. Often I had such cases for the Brazilian invoicing and often I could deal with it by adding a substitution lower casing the 1st field name letter. For instance https://github.com/akretion/nfelib/blob/master-xsdata/.xsdata.xml#L35 but eventually you have a better idea to fix it in the code. Do you think it's worth creating an issue for it?

sure why not :)
sonarcloud[bot]: SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=790)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=790&resolved=false&types=SECURITY_HOTSPOT) [![E](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/E-16px.png 'E')](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=790&resolved=false&types=SECURITY_HOTSPOT) [1 Security Hotspot](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=790&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=790) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=790&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=790&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=790)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=790&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=790&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=790&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=790&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=790) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=790&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=790&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/xsdata/codegen/handlers/flatten_class_extensions.py b/xsdata/codegen/handlers/flatten_class_extensions.py
index beb37e9d..4acc7fda 100644
--- a/xsdata/codegen/handlers/flatten_class_extensions.py
+++ b/xsdata/codegen/handlers/flatten_class_extensions.py
@@ -151,7 +151,7 @@ class FlattenClassExtensions(RelativeHandlerInterface):
         extension completely, copy all source attributes to the target
         class or leave the extension alone.
         """
-        if cls.should_remove_extension(source, target):
+        if cls.should_remove_extension(source, target, ext):
             target.extensions.remove(ext)
         elif cls.should_flatten_extension(source, target):
             ClassUtils.copy_attributes(source, target, ext)
@@ -177,7 +177,9 @@ class FlattenClassExtensions(RelativeHandlerInterface):
         return None
 
     @classmethod
-    def should_remove_extension(cls, source: Class, target: Class) -> bool:
+    def should_remove_extension(
+        cls, source: Class, target: Class, ext: Extension
+    ) -> bool:
         """
         Return whether the extension should be removed because of some
         violation.
@@ -185,10 +187,15 @@ class FlattenClassExtensions(RelativeHandlerInterface):
         Violations:
             - Circular Reference
             - Forward Reference
+            - Unordered sequences
             - MRO Violation A(B), C(B) and extensions includes A, B, C
         """
         # Circular or Forward reference
-        if source is target or target in source.inner:
+        if (
+            source is target
+            or target in source.inner
+            or cls.have_unordered_sequences(source, target, ext)
+        ):
             return True
 
         # MRO Violation
@@ -212,31 +219,41 @@ class FlattenClassExtensions(RelativeHandlerInterface):
             source.is_simple_type
             or target.has_suffix_attr
             or (source.has_suffix_attr and target.attrs)
-            or not cls.validate_sequence_order(source, target)
         ):
             return True
 
         return False
 
     @classmethod
-    def validate_sequence_order(cls, source: Class, target: Class) -> bool:
+    def have_unordered_sequences(
+        cls, source: Class, target: Class, ext: Extension
+    ) -> bool:
         """
         Validate sequence attributes are in the same order in the parent class.
 
         Dataclasses fields ordering follows the python mro pattern, the
-        parent fields are always first and they are updated if the
+        parent fields are always first, and they are updated if the
         subclass is overriding any of them but the overall ordering
         doesn't change!
+
+        @todo This needs a complete rewrite and most likely it needs to
+        @todo move way down in the process chain.
         """
+
+        if ext.tag == Tag.EXTENSION or source.extensions:
+            return False
+
         sequence = [
-            attr.name for attr in target.attrs if attr.restrictions.sequence is not None
+            attr.name
+            for attr in target.attrs
+            if attr.restrictions.sequence is not None and not attr.is_prohibited
         ]
         if len(sequence) > 1:
             compare = [attr.name for attr in source.attrs if attr.name in sequence]
             if compare and compare != sequence:
-                return False
+                return True
 
-        return True
+        return False
 
     @classmethod
     def replace_attributes_type(cls, target: Class, extension: Extension):
diff --git a/xsdata/codegen/handlers/validate_attributes_overrides.py b/xsdata/codegen/handlers/validate_attributes_overrides.py
index 51774e46..edef2247 100644
--- a/xsdata/codegen/handlers/validate_attributes_overrides.py
+++ b/xsdata/codegen/handlers/validate_attributes_overrides.py
@@ -34,6 +34,8 @@ class ValidateAttributesOverrides(RelativeHandlerInterface):
                     self.validate_override(target, attr, base_attr)
                 else:
                     self.resolve_conflict(attr, base_attr)
+            elif attr.is_prohibited:
+                self.remove_attribute(target, attr)
 
     @classmethod
     def overrides(cls, a: Attr, b: Attr) -> bool:
diff --git a/xsdata/codegen/mappers/dtd.py b/xsdata/codegen/mappers/dtd.py
index 0d3c8789..7a2370ea 100644
--- a/xsdata/codegen/mappers/dtd.py
+++ b/xsdata/codegen/mappers/dtd.py
@@ -118,7 +118,9 @@ class DtdMapper:
     @classmethod
     def build_extension(cls, target: Class, data_type: DataType):
         ext_type = AttrType(qname=str(data_type), native=True)
-        extension = Extension(type=ext_type, restrictions=Restrictions())
+        extension = Extension(
+            tag=Tag.EXTENSION, type=ext_type, restrictions=Restrictions()
+        )
         target.extensions.append(extension)
 
     @classmethod
diff --git a/xsdata/codegen/mappers/schema.py b/xsdata/codegen/mappers/schema.py
index 93d01cbb..d1376be5 100644
--- a/xsdata/codegen/mappers/schema.py
+++ b/xsdata/codegen/mappers/schema.py
@@ -114,7 +114,8 @@ class SchemaMapper:
 
         restrictions = obj.get_restrictions()
         extensions = [
-            cls.build_class_extension(target, base, restrictions) for base in obj.bases
+            cls.build_class_extension(obj.class_name, target, base, restrictions)
+            for base in obj.bases
         ]
         extensions.extend(cls.children_extensions(obj, target))
         target.extensions = collections.unique_sequence(extensions)
@@ -198,17 +199,20 @@ class SchemaMapper:
                 continue
 
             for ext in child.bases:
-                yield cls.build_class_extension(target, ext, child.get_restrictions())
+                yield cls.build_class_extension(
+                    child.class_name, target, ext, child.get_restrictions()
+                )
 
             yield from cls.children_extensions(child, target)
 
     @classmethod
     def build_class_extension(
-        cls, target: Class, name: str, restrictions: Dict
+        cls, tag: str, target: Class, name: str, restrictions: Dict
     ) -> Extension:
         """Create an extension for the target class."""
         return Extension(
             type=cls.build_data_type(target, name),
+            tag=tag,
             restrictions=Restrictions(**restrictions),
         )
 
@@ -228,9 +232,6 @@ class SchemaMapper:
         if obj.class_name in (Tag.ELEMENT, Tag.ANY, Tag.GROUP):
             restrictions.merge(parent_restrictions)
 
-        if restrictions.is_prohibited:
-            return
-
         name = obj.real_name
         target.attrs.append(
             Attr(
diff --git a/xsdata/codegen/models.py b/xsdata/codegen/models.py
index 3afdfc6b..76d7b1b7 100644
--- a/xsdata/codegen/models.py
+++ b/xsdata/codegen/models.py
@@ -301,6 +301,11 @@ class Attr:
         """Return whether this attribute is a list of values."""
         return self.restrictions.is_list
 
+    @property
+    def is_prohibited(self) -> bool:
+        """Return whether this attribute is prohibited."""
+        return self.restrictions.is_prohibited
+
     @property
     def is_nameless(self) -> bool:
         """Return whether this attribute has a local name that will be used
@@ -384,10 +389,12 @@ class Extension:
     """
     Model representation of a dataclass base class.
 
+    :param tag:
     :param type:
     :param restrictions:
     """
 
+    tag: str
     type: AttrType
     restrictions: Restrictions = field(hash=False)
 
diff --git a/xsdata/formats/dataclass/filters.py b/xsdata/formats/dataclass/filters.py
index c5c6fed7..54d2467d 100644
--- a/xsdata/formats/dataclass/filters.py
+++ b/xsdata/formats/dataclass/filters.py
@@ -19,6 +19,7 @@ from xsdata.codegen.models import Attr
 from xsdata.codegen.models import AttrType
 from xsdata.codegen.models import Class
 from xsdata.formats.converter import converter
+from xsdata.formats.dataclass.models.elements import XmlType
 from xsdata.models.config import DocstringStyle
 from xsdata.models.config import GeneratorConfig
 from xsdata.models.config import ObjectType
@@ -163,10 +164,10 @@ class Filters:
         metadata = self.field_metadata(attr, parent_namespace, parents)
 
         kwargs: Dict[str, Any] = {}
-        if attr.fixed:
+        if attr.fixed or attr.is_prohibited:
             kwargs["init"] = False
 
-        if default_value is not False:
+        if default_value is not False and not attr.is_prohibited:
             key = self.FACTORY_KEY if attr.is_factory else self.DEFAULT_KEY
             kwargs[key] = default_value
 
@@ -282,6 +283,9 @@ class Filters:
     ) -> Dict:
         """Return a metadata dictionary for the given attribute."""
 
+        if attr.is_prohibited:
+            return {"type": XmlType.IGNORE}
+
         name = namespace = None
 
         if not attr.is_nameless and attr.local_name != self.field_name(
@@ -588,6 +592,10 @@ class Filters:
 
     def field_type(self, attr: Attr, parents: List[str]) -> str:
         """Generate type hints for the given attribute."""
+
+        if attr.is_prohibited:
+            return "Any"
+
         type_names = collections.unique_sequence(
             self.field_type_name(x, parents) for x in attr.types
         )
@@ -703,6 +711,7 @@ class Filters:
                 "Tuple": ["Tuple["],
                 "Type": ["Type["],
                 "Union": ["Union["],
+                "Any": type_patterns("Any"),
             },
             "xml.etree.ElementTree": {"QName": type_patterns("QName")},
             "xsdata.models.datatype": {
diff --git a/xsdata/utils/text.py b/xsdata/utils/text.py
index 0a94069c..779786e4 100644
--- a/xsdata/utils/text.py
+++ b/xsdata/utils/text.py
@@ -7,6 +7,7 @@ from typing import Tuple
 
 stop_words = {
     "",
+    "Any",
     "Decimal",
     "Dict",
     "Enum",


Test patch:
diff --git a/tests/codegen/handlers/test_flatten_class_extensions.py b/tests/codegen/handlers/test_flatten_class_extensions.py
index 903c05aa..4b2f4b0f 100644
--- a/tests/codegen/handlers/test_flatten_class_extensions.py
+++ b/tests/codegen/handlers/test_flatten_class_extensions.py
@@ -293,7 +293,7 @@ class FlattenClassExtensionsTests(FactoryTestCase):
         self.assertEqual(0, len(target.extensions))
         self.assertEqual(1, len(target.attrs))
 
-        mock_should_remove_extension.assert_called_once_with(source, target)
+        mock_should_remove_extension.assert_called_once_with(source, target, extension)
         self.assertEqual(0, mock_copy_attributes.call_count)
         self.assertEqual(0, extension.type.reference)
 
@@ -343,23 +343,46 @@ class FlattenClassExtensionsTests(FactoryTestCase):
     def test_should_remove_extension(self):
         source = ClassFactory.create()
         target = ClassFactory.create()
+        extension = ExtensionFactory.create(tag=Tag.EXTENSION)
+        callback = self.processor.should_remove_extension
 
         # source is target
-        self.assertTrue(self.processor.should_remove_extension(source, source))
-        self.assertFalse(self.processor.should_remove_extension(source, target))
+        self.assertTrue(callback(source, source, extension))
+        self.assertFalse(callback(source, target, extension))
 
         # Source is parent class
         source.inner.append(target)
-        self.assertTrue(self.processor.should_remove_extension(target, target))
+        self.assertTrue(callback(target, target, extension))
 
         # MRO Violation
         source.inner.clear()
         target.extensions.append(ExtensionFactory.reference("foo"))
         target.extensions.append(ExtensionFactory.reference("bar"))
-        self.assertFalse(self.processor.should_remove_extension(source, target))
+        self.assertFalse(callback(source, target, extension))
 
         source.extensions.append(ExtensionFactory.reference("bar"))
-        self.assertTrue(self.processor.should_remove_extension(source, target))
+        self.assertTrue(callback(source, target, extension))
+
+        # Sequential violation
+        extension.tag = Tag.RESTRICTION
+        source = ClassFactory.elements(4)
+        target = source.clone()
+        self.assertFalse(callback(source, target, extension))
+
+        for attr in target.attrs:
+            attr.restrictions.sequence = 1
+
+        target.attrs[3].restrictions.max_occurs = 0
+
+        self.assertFalse(callback(source, target, extension))
+
+        target.attrs = [
+            target.attrs[1],
+            target.attrs[0],
+            target.attrs[2],
+            target.attrs[3],
+        ]
+        self.assertTrue(callback(source, target, extension))
 
     def test_should_flatten_extension(self):
         source = ClassFactory.create()
@@ -388,19 +411,6 @@ class FlattenClassExtensionsTests(FactoryTestCase):
         target = ClassFactory.elements(1)
         self.assertTrue(self.processor.should_flatten_extension(source, target))
 
-        # Sequential violation
-        source = ClassFactory.elements(3)
-        target = source.clone()
-        self.assertFalse(self.processor.should_flatten_extension(source, target))
-
-        for attr in target.attrs:
-            attr.restrictions.sequence = 1
-
-        self.assertFalse(self.processor.should_flatten_extension(source, target))
-
-        target.attrs = [target.attrs[1], target.attrs[0], target.attrs[2]]
-        self.assertTrue(self.processor.should_flatten_extension(source, target))
-
     def test_replace_attributes_type(self):
         extension = ExtensionFactory.create()
         target = ClassFactory.elements(2)
diff --git a/tests/codegen/handlers/test_validate_attributes_overrides.py b/tests/codegen/handlers/test_validate_attributes_overrides.py
index c8373798..78da4350 100644
--- a/tests/codegen/handlers/test_validate_attributes_overrides.py
+++ b/tests/codegen/handlers/test_validate_attributes_overrides.py
@@ -51,6 +51,13 @@ class ValidateAttributesOverridesTests(FactoryTestCase):
             class_a.attrs[1], class_c.attrs[1]
         )
 
+    def test_process_remove_non_overriding_prohibited_attrs(self):
+        target = ClassFactory.elements(1)
+        target.attrs[0].restrictions.max_occurs = 0
+
+        self.processor.process(target)
+        self.assertEqual(0, len(target.attrs))
+
     def test_overrides(self):
         a = AttrFactory.create(tag=Tag.SIMPLE_TYPE)
         b = a.clone()
diff --git a/tests/codegen/mappers/test_schema.py b/tests/codegen/mappers/test_schema.py
index 95e83d21..439b22ee 100644
--- a/tests/codegen/mappers/test_schema.py
+++ b/tests/codegen/mappers/test_schema.py
@@ -180,13 +180,14 @@ class SchemaMapperTests(FactoryTestCase):
         bar_type = AttrTypeFactory.create(qname="bar")
         foo_type = AttrTypeFactory.create(qname="foo")
 
-        bar = ExtensionFactory.create(bar_type)
-        double = ExtensionFactory.create(bar_type)
-        foo = ExtensionFactory.create(foo_type)
+        bar = ExtensionFactory.create(bar_type, tag=Tag.RESTRICTION)
+        double = ExtensionFactory.create(bar_type, tag=Tag.RESTRICTION)
+        foo = ExtensionFactory.create(foo_type, tag=Tag.EXTENSION)
 
         mock_children_extensions.return_value = [bar, double, foo]
         self_ext = ExtensionFactory.reference(
             qname="{xsdata}something",
+            tag=Tag.ELEMENT,
             restrictions=Restrictions(min_occurs=1, max_occurs=1),
         )
 
@@ -253,15 +254,16 @@ class SchemaMapperTests(FactoryTestCase):
 
         item = ClassFactory.create(ns_map={"bk": "book"})
         children = SchemaMapper.children_extensions(complex_type, item)
-        expected = list(
-            map(
-                ExtensionFactory.create,
-                [
-                    AttrTypeFactory.create(qname=build_qname("book", "b")),
-                    AttrTypeFactory.create(qname=build_qname("book", "c")),
-                ],
-            )
-        )
+        expected = [
+            ExtensionFactory.create(
+                AttrTypeFactory.create(qname=build_qname("book", "b")),
+                tag=Tag.RESTRICTION,
+            ),
+            ExtensionFactory.create(
+                AttrTypeFactory.create(qname=build_qname("book", "c")),
+                tag=Tag.EXTENSION,
+            ),
+        ]
 
         self.assertIsInstance(children, GeneratorType)
         self.assertEqual(expected, list(children))
@@ -319,12 +321,6 @@ class SchemaMapperTests(FactoryTestCase):
         mock_build_class_attribute_types.assert_called_once_with(item, attribute)
         mock_element_namespace.assert_called_once_with(attribute, item.target_namespace)
 
-    def test_build_class_attribute_skip_prohibited(self):
-        item = ClassFactory.create(ns_map={"bar": "foo"})
-        attribute = Attribute(use=UseType.PROHIBITED)
-        SchemaMapper.build_class_attribute(item, attribute, Restrictions())
-        self.assertEqual(0, len(item.attrs))
-
     @mock.patch.object(Attribute, "attr_types", new_callable=mock.PropertyMock)
     @mock.patch.object(SchemaMapper, "build_inner_classes")
     def test_build_class_attribute_types(
diff --git a/tests/codegen/models/test_attr.py b/tests/codegen/models/test_attr.py
index 1e957cb9..7429d024 100644
--- a/tests/codegen/models/test_attr.py
+++ b/tests/codegen/models/test_attr.py
@@ -63,6 +63,13 @@ class AttrTests(FactoryTestCase):
         attr.restrictions.max_occurs = 1
         self.assertFalse(attr.is_list)
 
+    def test_property_is_prohibited(self):
+        attr = AttrFactory.create(restrictions=Restrictions(max_occurs=0))
+        self.assertTrue(attr.is_prohibited)
+
+        attr.restrictions.max_occurs = 1
+        self.assertFalse(attr.is_list)
+
     def test_property_is_optional(self):
         attr = AttrFactory.create(restrictions=Restrictions(min_occurs=0))
         self.assertTrue(attr.is_optional)
diff --git a/tests/formats/dataclass/test_filters.py b/tests/formats/dataclass/test_filters.py
index aa095d30..e923fb7d 100644
--- a/tests/formats/dataclass/test_filters.py
+++ b/tests/formats/dataclass/test_filters.py
@@ -145,6 +145,22 @@ class FiltersTests(FactoryTestCase):
         )
         self.assertEqual(expected, result)
 
+    def test_field_definition_with_prohibited_attr(self):
+        attr = AttrFactory.native(DataType.INT)
+        attr.restrictions.max_occurs = 0
+        attr.default = "1"
+
+        result = self.filters.field_definition(attr, {}, None, ["Root"])
+        expected = (
+            "field(\n"
+            "        init=False,\n"
+            "        metadata={\n"
+            '            "type": "Ignore",\n'
+            "        }\n"
+            "    )"
+        )
+        self.assertEqual(expected, result)
+
     @mock.patch.object(Filters, "field_default_value")
     def test_field_definition_with_restriction_pattern(self, mock_field_default_value):
         mock_field_default_value.return_value = None
@@ -538,6 +554,11 @@ class FiltersTests(FactoryTestCase):
         )
         self.assertEqual("Optional[int]", self.filters.field_type(attr, ["a", "b"]))
 
+    def test_field_type_with_prohibited_attr(self):
+        attr = AttrFactory.create(restrictions=Restrictions(max_occurs=0))
+
+        self.assertEqual("Any", self.filters.field_type(attr, ["a", "b"]))
+
     def test_choice_type(self):
         choice = AttrFactory.create(types=[AttrTypeFactory.create("foobar")])
         actual = self.filters.choice_type(choice, ["a", "b"])
@@ -656,6 +677,10 @@ class FiltersTests(FactoryTestCase):
         expected = "from typing import Type"
         self.assertIn(expected, self.filters.default_imports(output))
 
+        output = ": Any = "
+        expected = "from typing import Any"
+        self.assertIn(expected, self.filters.default_imports(output))
+
     def test_default_imports_combo(self):
         output = (
             "@dataclass\n"
diff --git a/xsdata/utils/testing.py b/xsdata/utils/testing.py
index 26cd753a..1f6db409 100644
--- a/xsdata/utils/testing.py
+++ b/xsdata/utils/testing.py
@@ -196,24 +196,30 @@ class ClassFactory(Factory):
 
 class ExtensionFactory(Factory):
     counter = 65
+    tags = [Tag.ELEMENT, Tag.EXTENSION, Tag.RESTRICTION]
 
     @classmethod
     def create(
         cls,
         attr_type: Optional[AttrType] = None,
         restrictions: Optional[Restrictions] = None,
+        tag: Optional[str] = None,
         **kwargs: Any,
     ) -> Extension:
         return Extension(
+            tag=tag or random.choice(cls.tags),
             type=attr_type or AttrTypeFactory.create(**kwargs),
             restrictions=restrictions or Restrictions(),
         )
 
     @classmethod
     def reference(cls, qname: str, **kwargs: Any) -> Extension:
+        tag = kwargs.pop("tag", None)
         restrictions = kwargs.pop("restrictions", None)
         return cls.create(
-            AttrTypeFactory.create(qname=qname, **kwargs), restrictions=restrictions
+            AttrTypeFactory.create(qname=qname, **kwargs),
+            tag=tag,
+            restrictions=restrictions,
         )
 
     @classmethod