Repository: tefra/xsdata

Issue:
substitutionGroup not detected during model generation
I try to use XSDATA to parse Business Process Model and Notation (BPMN) 2.0.2 diagrams.
https://www.omg.org/spec/BPMN/2.0.2/

The XS schema contains a _substitutionGroup_ Element that is not detected during model generation. When parsing a valid BPMN XML file using the generated models an "Unknown property" occurs.

A working example with full error description and details (schema, generated model, parser code, name of substitutionGroup) can be found here:

https://github.com/THM-MA/xsdata-substGrp

I've already tried different structure styles (filenames, namespaces, clusters, usw.) to avoid namespace conflicts without success.

The XSDATA documentation 21.8 (2021-08-03) mentions _„Updated fields derived from xs:substitutionGroups to optional”_. May this be the problem?

Any help is highly appreciated!

Thanks
Thomas



Discussion:

Patch:
diff --git a/xsdata/codegen/handlers/attribute_substitution.py b/xsdata/codegen/handlers/attribute_substitution.py
index cbe3acce..c79eaf6b 100644
--- a/xsdata/codegen/handlers/attribute_substitution.py
+++ b/xsdata/codegen/handlers/attribute_substitution.py
@@ -9,6 +9,7 @@ from xsdata.codegen.models import Attr
 from xsdata.codegen.models import AttrType
 from xsdata.codegen.models import Class
 from xsdata.codegen.utils import ClassUtils
+from xsdata.models.enums import Tag
 from xsdata.utils import collections
 
 
@@ -82,6 +83,6 @@ class AttributeSubstitutionHandler(RelativeHandlerInterface):
         return Attr(
             name=source.name,
             types=[AttrType(qname=source.qname)],
-            tag=source.tag,
+            tag=Tag.ELEMENT,
             namespace=source.namespace,
         )
diff --git a/xsdata/codegen/validator.py b/xsdata/codegen/validator.py
index 0271842e..68da50e7 100644
--- a/xsdata/codegen/validator.py
+++ b/xsdata/codegen/validator.py
@@ -156,4 +156,5 @@ class ClassValidator:
 
         ct.namespace = el.namespace or ct.namespace
         ct.help = el.help or ct.help
+        ct.substitutions = el.substitutions
         classes.remove(el)


Test patch:
diff --git a/tests/codegen/handlers/test_attribute_substitution.py b/tests/codegen/handlers/test_attribute_substitution.py
index fd3672fb..9066be47 100644
--- a/tests/codegen/handlers/test_attribute_substitution.py
+++ b/tests/codegen/handlers/test_attribute_substitution.py
@@ -4,6 +4,7 @@ from xsdata.codegen.container import ClassContainer
 from xsdata.codegen.handlers import AttributeSubstitutionHandler
 from xsdata.codegen.models import AttrType
 from xsdata.models.config import GeneratorConfig
+from xsdata.models.enums import Tag
 from xsdata.utils.namespaces import build_qname
 from xsdata.utils.testing import AttrFactory
 from xsdata.utils.testing import AttrTypeFactory
@@ -116,7 +117,7 @@ class AttributeSubstitutionHandlerTests(FactoryTestCase):
             name=item.name,
             default=None,
             types=[AttrType(qname=build_qname("foo", "bar"))],
-            tag=item.tag,
+            tag=Tag.ELEMENT,
         )
 
         self.assertEqual(expected, actual)
diff --git a/tests/codegen/test_validator.py b/tests/codegen/test_validator.py
index fee88f85..9ac070bc 100644
--- a/tests/codegen/test_validator.py
+++ b/tests/codegen/test_validator.py
@@ -93,8 +93,14 @@ class ClassValidatorTests(FactoryTestCase):
         )
 
     def test_merge_global_types(self):
-        one = ClassFactory.create(qname="foo", tag=Tag.ELEMENT, namespace="a", help="b")
-        two = ClassFactory.create(qname="foo", tag=Tag.COMPLEX_TYPE)
+        one = ClassFactory.create(
+            qname="foo",
+            tag=Tag.ELEMENT,
+            namespace="a",
+            help="b",
+            substitutions=["a", "b"],
+        )
+        two = ClassFactory.create(qname="foo", tag=Tag.COMPLEX_TYPE, substitutions=[])
         three = ClassFactory.create(qname="foo", tag=Tag.SIMPLE_TYPE)
 
         classes = [one, two, three]
@@ -128,6 +134,8 @@ class ClassValidatorTests(FactoryTestCase):
         self.assertIn(three, classes)
         self.assertEqual(one.namespace, two.namespace)
         self.assertEqual(one.help, two.help)
+        self.assertEqual(one.substitutions, two.substitutions)
+        self.assertEqual(2, len(one.substitutions))
 
     @mock.patch.object(ClassUtils, "copy_extensions")
     @mock.patch.object(ClassUtils, "copy_attributes")