0

I'm trying to generate some classes from xsd definitions with a xsd:redefine tag on Visual Studio 2019, but it enters an infinite loop on Xsd2Code++ Version 5.0.0.47.

This is a simplification of my example:

File Cabecera.xsd:

    <?xml version="1.0" encoding="utf-8"?>
    <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:sii="https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/ssii/fact/ws/SuministroInformacion.xsd" targetNamespace="https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/ssii/fact/ws/SuministroInformacion.xsd" elementFormDefault="qualified">
      <simpleType name="VersionSiiType">
        <restriction base="string" />
      </simpleType>
      <simpleType name="ClaveTipoComunicacionType">
        <restriction base="string" />
      </simpleType>
      <simpleType name="TextMax120Type">
        <restriction base="string">
          <maxLength value="120"/>
        </restriction>
      </simpleType>
      <simpleType name="CIFTypeB">
        <annotation>
          <documentation xml:lang="es">CIF: Blanco, CIF o Secuencia de 9 dígitos o letras mayúsculas</documentation>
        </annotation>
        <restriction base="string">
          <pattern value="((^[a-z|A-Z]{1}\d{7}[a-z|A-Z]{1}$)|(^\d{8}[a-z|A-Z]{1}$)|(^[a-z|A-Z]{1}\d{8}$)|^$|^ {9}$|^[a-z|A-Z]{2}\d{11}$)"/>
        </restriction>
      </simpleType>
      <simpleType name="NIFType">
        <annotation>
          <documentation xml:lang="es">NIF: Secuencia de 9 dígitos o letras mayúsculas</documentation>
        </annotation>
        <restriction base="string">
          <length value="9"/>
          <pattern value="(([a-z|A-Z]{1}\d{7}[a-z|A-Z]{1})|(\d{8}[a-z|A-Z]{1})|([a-z|A-Z]{1}\d{8}))"/>
        </restriction>
      </simpleType>
      <complexType name="CabeceraSiiVersion">
        <annotation>
          <documentation xml:lang="es"> Datos de contexto de un suministro </documentation>
        </annotation>
        <sequence>
          <element name="IDVersionSii" type="sii:VersionSiiType"/>
        </sequence>
      </complexType>
      <complexType name="PersonaFisicaJuridicaESType">
        <annotation>
          <documentation xml:lang="es">Datos de una persona física o jurídica Española con un NIF asociado</documentation>
        </annotation>
        <sequence>
          <element name="NombreRazon" type="sii:TextMax120Type"/>
          <element name="NIFRepresentante" type="sii:CIFTypeB" minOccurs="0"/>
          <element name="NIF" type="sii:NIFType"/>
        </sequence>
      </complexType>
      <complexType name="CabeceraSiiSinTC">
        <annotation>
          <documentation xml:lang="es"> Datos de contexto de un suministro sin especificar el tipo de comunicacion </documentation>
        </annotation>
        <complexContent>
          <extension base="sii:CabeceraSiiVersion">
            <sequence>
              <element name="Titular" type="sii:PersonaFisicaJuridicaESType">
                <annotation>
                  <documentation xml:lang="es"> Titular de los libros de registro que suministra la información </documentation>
                </annotation>
              </element>
            </sequence>
          </extension>
        </complexContent>
      </complexType>
      <complexType name="CabeceraSii">
        <annotation>
          <documentation xml:lang="es"> Datos de contexto de un suministro sin especificar el tipo de comunicacion </documentation>
        </annotation>
        <complexContent>
          <extension base="sii:CabeceraSiiSinTC">
            <sequence>
              <element name="TipoComunicacion" type="sii:ClaveTipoComunicacionType"/>
            </sequence>
          </extension>
        </complexContent>
      </complexType>
    </schema>

File SuministroInformacion.xsd

    <?xml version="1.0" encoding="UTF-8"?>
    <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:sii="https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/ssii/fact/ws/SuministroInformacion.xsd" targetNamespace="https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/ssii/fact/ws/SuministroInformacion.xsd" elementFormDefault="qualified">
      <include schemaLocation="Cabecera.xsd" />
      <redefine schemaLocation="Cabecera.xsd">
        <simpleType name="VersionSiiType">
          <restriction base="sii:VersionSiiType">
            <enumeration value="1.0"/>
          </restriction>
        </simpleType>  
        <simpleType name="ClaveTipoComunicacionType">
          <restriction base="sii:ClaveTipoComunicacionType">
            <enumeration value="A0">
              <annotation>
                <documentation xml:lang="es"> A0 Alta (Se añade al libro un registro una nueva factura)</documentation>
              </annotation>
            </enumeration>
            <enumeration value="A1">
              <annotation>
                <documentation xml:lang="es"> A1 Modificación (La información que se comunica sustituye a la existente relacionada)</documentation>
              </annotation>
            </enumeration>
            <enumeration value="A4">
              <annotation>
                <documentation xml:lang="es"> Modificación Factura Régimen de Viajeros</documentation>
              </annotation>
            </enumeration>
          </restriction>
        </simpleType>
      </redefine>  
      <!-- Suministro genérico -->
      <complexType name="SuministroInformacion">
        <annotation>
          <documentation xml:lang="es">
            Sii - Suministro Inmediato de Información, compuesto por datos
            de contexto y una secuencia de 1 o más registros.
          </documentation>
        </annotation>
        <sequence>
          <element name="Cabecera" type="sii:CabeceraSii"/>
        </sequence>
      </complexType>
    </schema>

The generation options are as follows:

  • Cabecera.xsd:
  • <?xml version="1.0" encoding="utf-8"?>
    <auto-generated>
      <NameSpace>Negocio</NameSpace>
      <Collection>List</Collection>
      <codeType>CSharp</codeType>
      <EnableDataBinding>False</EnableDataBinding>
      <GenerateCloneMethod>False</GenerateCloneMethod>
      <GenerateDataContracts>False</GenerateDataContracts>
      <DataMemberNameArg>OnlyIfDifferent</DataMemberNameArg>
      <DataMemberOnXmlIgnore>False</DataMemberOnXmlIgnore>
      <CodeBaseTag>Net40</CodeBaseTag>
      <InitializeFields>All</InitializeFields>
      <GenerateUnusedComplexTypes>True</GenerateUnusedComplexTypes>
      <GenerateUnusedSimpleTypes>True</GenerateUnusedSimpleTypes>
      <GenerateXMLAttributes>True</GenerateXMLAttributes>
      <OrderXMLAttrib>False</OrderXMLAttrib>
      <EnableLazyLoading>False</EnableLazyLoading>
      <VirtualProp>False</VirtualProp>
      <PascalCase>False</PascalCase>
      <AutomaticProperties>True</AutomaticProperties>
      <PropNameSpecified>None</PropNameSpecified>
      <PrivateFieldName>StartWithUnderscore</PrivateFieldName>
      <PrivateFieldNamePrefix></PrivateFieldNamePrefix>
      <EnableRestriction>False</EnableRestriction>
      <RestrictionMaxLenght>False</RestrictionMaxLenght>
      <RestrictionRegEx>False</RestrictionRegEx>
      <RestrictionRange>False</RestrictionRange>
      <ValidateProperty>False</ValidateProperty>
      <ClassNamePrefix></ClassNamePrefix>
      <ClassLevel>Public</ClassLevel>
      <PartialClass>True</PartialClass>
      <ClassesInSeparateFiles>False</ClassesInSeparateFiles>
      <ClassesInSeparateFilesDir></ClassesInSeparateFilesDir>
      <TrackingChangesEnable>False</TrackingChangesEnable>
      <GenTrackingClasses>False</GenTrackingClasses>
      <HidePrivateFieldInIDE>False</HidePrivateFieldInIDE>
      <EnableSummaryComment>False</EnableSummaryComment>
      <EnableAppInfoSettings>False</EnableAppInfoSettings>
      <EnableExternalSchemasCache>False</EnableExternalSchemasCache>
      <EnableDebug>False</EnableDebug>
      <EnableWarn>False</EnableWarn>
      <ExcludeImportedTypes>True</ExcludeImportedTypes>
      <ExpandNesteadAttributeGroup>False</ExpandNesteadAttributeGroup>
      <CleanupCode>False</CleanupCode>
      <EnableXmlSerialization>False</EnableXmlSerialization>
      <SerializeMethodName>Serialize</SerializeMethodName>
      <DeserializeMethodName>Deserialize</DeserializeMethodName>
      <SaveToFileMethodName>SaveToFile</SaveToFileMethodName>
      <LoadFromFileMethodName>LoadFromFile</LoadFromFileMethodName>
      <EnableEncoding>False</EnableEncoding>
      <EnableXMLIndent>False</EnableXMLIndent>
      <IndentChar>Indent2Space</IndentChar>
      <NewLineAttr>False</NewLineAttr>
      <OmitXML>False</OmitXML>
      <Encoder>UTF8</Encoder>
      <Serializer>XmlSerializer</Serializer>
      <sspNullable>False</sspNullable>
      <sspString>False</sspString>
      <sspCollection>False</sspCollection>
      <sspComplexType>False</sspComplexType>
      <sspSimpleType>False</sspSimpleType>
      <sspEnumType>False</sspEnumType>
      <XmlSerializerEvent>False</XmlSerializerEvent>
      <BaseClassName>EntityBase</BaseClassName>
      <UseBaseClass>False</UseBaseClass>
      <GenBaseClass>False</GenBaseClass>
      <CustomUsings></CustomUsings>
      <AttributesToExlude></AttributesToExlude>
    </auto-generated>
    

  • SuministroInformacion.xsd:
  • <?xml version="1.0" encoding="utf-8"?>
    <auto-generated>
      <NameSpace>Negocio</NameSpace>
      <Collection>List</Collection>
      <codeType>CSharp</codeType>
      <EnableDataBinding>False</EnableDataBinding>
      <GenerateCloneMethod>False</GenerateCloneMethod>
      <GenerateDataContracts>False</GenerateDataContracts>
      <DataMemberNameArg>OnlyIfDifferent</DataMemberNameArg>
      <DataMemberOnXmlIgnore>False</DataMemberOnXmlIgnore>
      <CodeBaseTag>Net40</CodeBaseTag>
      <InitializeFields>All</InitializeFields>
      <GenerateUnusedComplexTypes>True</GenerateUnusedComplexTypes>
      <GenerateUnusedSimpleTypes>True</GenerateUnusedSimpleTypes>
      <GenerateXMLAttributes>True</GenerateXMLAttributes>
      <OrderXMLAttrib>False</OrderXMLAttrib>
      <EnableLazyLoading>False</EnableLazyLoading>
      <VirtualProp>False</VirtualProp>
      <PascalCase>False</PascalCase>
      <AutomaticProperties>True</AutomaticProperties>
      <PropNameSpecified>None</PropNameSpecified>
      <PrivateFieldName>StartWithUnderscore</PrivateFieldName>
      <PrivateFieldNamePrefix></PrivateFieldNamePrefix>
      <EnableRestriction>False</EnableRestriction>
      <RestrictionMaxLenght>False</RestrictionMaxLenght>
      <RestrictionRegEx>False</RestrictionRegEx>
      <RestrictionRange>False</RestrictionRange>
      <ValidateProperty>False</ValidateProperty>
      <ClassNamePrefix></ClassNamePrefix>
      <ClassLevel>Public</ClassLevel>
      <PartialClass>True</PartialClass>
      <ClassesInSeparateFiles>False</ClassesInSeparateFiles>
      <ClassesInSeparateFilesDir></ClassesInSeparateFilesDir>
      <TrackingChangesEnable>False</TrackingChangesEnable>
      <GenTrackingClasses>False</GenTrackingClasses>
      <HidePrivateFieldInIDE>False</HidePrivateFieldInIDE>
      <EnableSummaryComment>False</EnableSummaryComment>
      <EnableAppInfoSettings>False</EnableAppInfoSettings>
      <EnableExternalSchemasCache>False</EnableExternalSchemasCache>
      <EnableDebug>False</EnableDebug>
      <EnableWarn>False</EnableWarn>
      <ExcludeImportedTypes>True</ExcludeImportedTypes>
      <ExpandNesteadAttributeGroup>False</ExpandNesteadAttributeGroup>
      <CleanupCode>False</CleanupCode>
      <EnableXmlSerialization>False</EnableXmlSerialization>
      <SerializeMethodName>Serialize</SerializeMethodName>
      <DeserializeMethodName>Deserialize</DeserializeMethodName>
      <SaveToFileMethodName>SaveToFile</SaveToFileMethodName>
      <LoadFromFileMethodName>LoadFromFile</LoadFromFileMethodName>
      <EnableEncoding>False</EnableEncoding>
      <EnableXMLIndent>False</EnableXMLIndent>
      <IndentChar>Indent2Space</IndentChar>
      <NewLineAttr>False</NewLineAttr>
      <OmitXML>False</OmitXML>
      <Encoder>UTF8</Encoder>
      <Serializer>XmlSerializer</Serializer>
      <sspNullable>False</sspNullable>
      <sspString>False</sspString>
      <sspCollection>False</sspCollection>
      <sspComplexType>False</sspComplexType>
      <sspSimpleType>False</sspSimpleType>
      <sspEnumType>False</sspEnumType>
      <XmlSerializerEvent>False</XmlSerializerEvent>
      <BaseClassName>EntityBase</BaseClassName>
      <UseBaseClass>False</UseBaseClass>
      <GenBaseClass>False</GenBaseClass>
      <CustomUsings></CustomUsings>
      <AttributesToExlude></AttributesToExlude>
    </auto-generated>
    

    If i remove the redefine part on SuministroInformacion.xsd, the generation ends without problem.

    Best regards,
    Foltak

    Foltak
    • 11
    • 2
    • What is the xs:redefine trying to achieve? – kimbert May 14 '20 at 14:15
    • Good question. With the simplification the purpose to make this definition is not clear, it can't be achieved its goal. The point is that i have another xsd SuministroInformacion11.xsd that has another definition for the redefined types. For example with VersionSiiType will be: . And the final definition will be a virtual property of type string, with one override for the "1.0" and another one with the value "1.1" – Foltak May 15 '20 at 17:24
    • I'm not a big fan of xs:redefine. In this case, I think the same goals could be achieved by declaring the base simple base type as abstract, and defining and using subtypes with enums in the child schemas. But maybe you don't have control of these XSDs so you have no choice? – kimbert May 15 '20 at 18:49
    • If i make the definition directly on c# i've no problem to make them as abstract and override them on derived classes. But the goal is to make the same available on a xsd schema and generate automatically with Xsd2code++. This is a simplification of the schemas with only the types that reproduce the problem, but the schemas has a lot more info on types, classes, et all. And the point is the program hangs trying to generate the schemas, if i remove the redefined part, and make it myself i can bypass the problem, but maybe in the future that can derived in an unsolved problem. – Foltak May 16 '20 at 09:51

    2 Answers2

    0

    I think I have enough information to provide an answer now.

    Diagnosis

    This simple type definition in SuministroInformacion.xsd looks invalid to me. The base type could resolve to sii:VersionSiiType from Cabecera.xsd, or it could resolve to the redefined version in SuministroInformacion.xsd (which would be a recursive definition, and is probably the cause of the infinite loop).

            <simpleType name="VersionSiiType">
              <restriction base="sii:VersionSiiType">
                <enumeration value="1.0"/>
              </restriction>
    

    xsd2code++ should validate the XSD before it tries to generate code from it, so in my opinion that's a bug in xsd2code++.

    Alternative solution to avoid the defect

    As I said in the comments, xs:redefine should only be used when there is no alternative. In this case, there is a very good alternative. Object-oriented languages allow a type to be 'abstract'. So does XML Schema. Object-oriented languages allow type inheritance. So does XML Schema. I think you can achieve all of your goals without triggering this defect in xsd2code++.

    Step 1: For each type in Cabecera.xsd that should always be overridden, define it as abstract using abstract="true" in the type definition.

    Step 2: For each xs:redefine, remove the redefine and change the type name (or if you prefer, change the targetNamespace of the schema and leave the name unchanged). Add the enums or other facets exactly as before using <xs:restriction>

    Obviously, this will change the name or namespace of the sub-types. You were probably trying to avoid that by using xs:redefine. But you should avoid having two or more type definitions with identical names and different meanings. Think again about your real requirements.

    If you need to refer to a specific sub-type in your other XSDs, you can do that easily. But if you want the other XSDs to refer to a single simple type then

    • specify the base type
    • add an xsi:type attribute in your XML documents to identify which sub-type you want to validate against. Feel free to ask for more information on this technique.
    kimbert
    • 2,376
    • 1
    • 10
    • 20
    • i can't agree with you. The XSD definitions are correct because if i use them on the validation of a xml document there aren't any problem. These defintions are used not only with serializations purposes but also to validate the input on xml files. On the other part, the abstract=true can only be used on complex types, not on simple ones. See https://www.w3schools.com/xml/el_complextype.asp and https://www.w3schools.com/xml/el_simpletype.asp. – Foltak May 18 '20 at 15:26
    • If i change the type name, as you said, the general types defined on Cabecera.Xsd will not be the same on field types, thus needing to generate them again on derived classes, losing its purpose of generalization on Cabecera.Xsd – Foltak May 18 '20 at 15:28
    • I accept that the XSD may be valid, but I'm still not keen on xs:redefines in general. I also don't like your usage of xs:redefine. The whole point of a type definition is to give a unique name to a _value space_ (an allowed set of values for a tag). You are using the same name for multiple different value spaces. That's generally not a great idea, which is why XML Schema provides strong support for the alternative approach. – kimbert May 18 '20 at 21:43
    0

    After analysis of the xsd2code++ source code and debugging, there is indeed an infinite loop which is caused by the ImportTypeMapping method of the XmlSchemaImporter class.

    The problem is therefore in the Microsoft Framework itself. It may be possible to fix this case in xsd2code++ by building a new schema that integrates the new definitions. This seems a rather complex algorithm to implement but that seem to be possible.

    This problem has been referenced to the support team of xsd2code++ so that a solution can be found.

    xsd.exe which also uses XmlSchemaImporter also causes an infinite loop.

    • As i told before, i'm using XDocument.Validate to load all the schemes and validate XML files without any issue. – Foltak May 19 '20 at 19:11