Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

minOccurs="0" with maxOccurs="1" should generate a property and not a collection #475

Open
philhunt-ob opened this issue Dec 31, 2023 · 2 comments

Comments

@philhunt-ob
Copy link

This schema fragment
<xs:element name="IsDeprecated" type="YesNo_t" default="No" minOccurs="0"/>

is being generated as

public System.Collections.ObjectModel.Collection<YesNoT> IsDeprecated { ...

XSD default value for both minOccurs and maxOccurs is 1 so the above schema fragment is the same as

<xs:element name="IsDeprecated" type="YesNo_t" default="No" minOccurs="0" maxOccurs="1"/>

minOccurrs="0" and maxOccurs="1" is stating that this is an optional value but NOT a collection. Therefore, this should generate

public YesNoT IsDeprecated { ... } = YesNoT.No

Note: If default is not specified the generated code should be

public YesNoT? IsDeprecated { ... }

Note: XSD.exe correctly generates

public YesNo_t IsDeprecated { ...

@philhunt-ob
Copy link
Author

I looked into this some more. It has to do with <xs:sequence maxOccurs="unbounded"> along with Generate Interfaces. Normally minOccurs="0" works as expected.

The following simplified XSD has BooleanType that references group NodeElementTemplate and also ConfRomType that has a sequence with maxOccurs="unbounded" that references group NodeElementTemplate.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema>
  <xs:group name="NodeElementTemplate">
	  <xs:sequence>
		  <xs:element name="Extension" type="ExtensionType" minOccurs="0"/>
		  <xs:element name="IsDeprecated" type="YesNo_t" default="No" minOccurs="0"/>
	  </xs:sequence>
  </xs:group>
  <xs:complexType name="BooleanType">
	  <xs:sequence>
		  <xs:group ref="NodeElementTemplate"/>
		  <xs:element name="Streamable" type="YesNo_t" default="No" minOccurs="0"/>
	  </xs:sequence>
	  <xs:attributeGroup ref="NodeAttributeTemplate"/>
  </xs:complexType>
  <xs:complexType name="ConfRomType">
	  <xs:sequence maxOccurs="unbounded">
		  <xs:group ref="NodeElementTemplate"/>
		  <xs:element name="Unit" type="HexOrDecimal_t"/>
	  </xs:sequence>
	  <xs:attributeGroup ref="NodeAttributeTemplate"/>
  </xs:complexType>
</xsd>

The code that is generated for the interface INodeElementTemplate makes all of the properties (such as Extension and IsDeprecated) a Collection<> because ConfRomType has an unbounded sequence so ConfRomType needs for each property to be an array but for BooleanType (and about 10 other types that are not included in simplified schema) the properties should be properties and not collections. The problem appears to be the calculation of the interface, mistakenly escalating every property to be a collection in the interface. In my opinion ConfRomType should not implement the INodeElementTemplate interface since it includes an unbounded sequence of NodeElementTemplate and therefore is not implementing the interface but a collection of the properties in the interface.

Work around is to comment out ConfRomType and generate interfaces. Then uncomment ConfRomType and no longer generate interfaces, then manually add the interfaces back to the partial classes.

@mganss
Copy link
Owner

mganss commented Jan 12, 2024

@philhunt-ob I agree. This was introduced through the fix for #305 (see commit 7fb5352). Would you like to take a crack at fixing this? Since the current behavior is here already and might actually benefit some use cases, perhaps we can make behavior configurable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants