xsd2Code++ redefine tag deserialization not working

356 Views Asked by At

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

    2

    There are 2 best solutions below

    3
    kimbert On

    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.
    1
    xsd2code support On

    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.