XmlSchemaClassGenerator

repository·master·Indexed 20 days ago

https://github.com/mganss/xmlschemaclassgenerator

A tool and library for generating C# classes from XML Schema (XSD) files compatible with XmlSerializer. It provides advanced features beyond xsd.exe, including namespace mapping, nullable adapter properties, custom type substitution, and the ability to generate interfaces for XSD groups. It is available as a .NET Core CLI tool (dotnet-xscgen), a console application, or a C# library via the XmlSchemaClassGenerator-beta NuGet package.

Tokens
2.4K
Snippets
10
Records
10
Agent score
23%

What's inside XmlSchemaClassGenerator

  1. How nullable adapter properties work

    master

    Since XmlSerializer does not natively support .NET nullable types for value types, the generator can create an 'adapter' pattern to signal the presence or absence of a value.

    When --nullable is enabled, the generator produces:

    1. A raw value property (e.g., int IdValue) decorated with [XmlIgnore].
    2. A Specified boolean property (e.g., bool IdValueSpecified) to signal serialization.
    3. A nullable wrapper property (e.g., int? Id) that acts as an interface for the user, internally managing the IdValue and IdValueSpecified properties.

    Example Output:

    [System.Xml.Serialization.XmlAttributeAttribute("id", Form=System.Xml.Schema.XmlSchemaForm.Unqualified, DataType="int")]
    public int IdValue { get; set; }
    
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public bool IdValueSpecified { get; set; }
    
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public System.Nullable<int> Id
    {
        get { return this.IdValueSpecified ? this.IdValue : (int?)null; }
        set 
        {
            this.IdValue = value.GetValueOrDefault();
            this.IdValueSpecified = value.HasValue;
        }
    }
    // Example of the generated pattern
    [System.Xml.Serialization.XmlAttributeAttribute("id", Form=System.Xml.Schema.XmlSchemaForm.Unqualified, DataType="int")]
    public int IdValue { get; set; }
    
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public bool IdValueSpecified { get; set; }
    
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public System.Nullable<int> Id
    {
        get { return this.IdValueSpecified ? this.IdValue : (int?)null; }
        set 
        {
            this.IdValue = value.GetValueOrDefault();
            this.IdValueSpecified = value.HasValue;
        }
    }
  2. How interfaces are generated for groups

    master

    XML Schema xs:group and xs:attributeGroup are reusable components. To make these easily accessible across different classes, the generator can optionally create C# interfaces.

    If a group is defined in the schema, the generator creates a partial interface containing the group's members. Any class that includes that group will then implement that interface.

    Example: If an attributeGroup named Common contains a name attribute, and is referenced by classes A and B, the generator produces:

    public partial interface ICommon
    {
      string Name { get; set; }
    }
    
    public partial class A: ICommon
    {
      public string Name { get; set; }
    }
    
    public partial class B: ICommon
    {
      public string Name { get; set; }
    }
    public partial interface ICommon
    {
      string Name { get; set; }
    }
    
    public partial class A: ICommon
    {
      public string Name { get; set; }
    }
    
    public partial class B: ICommon
    {
      public string Name { get; set; }
    }
  3. Substitute generated C# type and member names

    master

    If your XSD uses obscure names, you can substitute them using the --tns (command line) or --tnsf (mapping file) options.

    Syntax: {kindId}:{generatedName}={substituteName}

    Valid kindId values:

    • P: Property
    • T: Type (class, enum, interface)
    • A: Any property and/or type

    Example CLI usage:

    xscgen --tns T:Example_RootType=Example --tns P:StartDateDateTimeValue=StartDate example.xsd

    Example mapping file content:

    # Comment
    T:Example_RootType = Example
    T:Example_RootTypeExampleScope = ExampleScope
    P:StartDateDateTimeValue = StartDate
    xscgen --tnsf substitutions.txt example.xsd
  4. Map XSD files to specific C# namespaces

    master

    By default, the generator creates C# namespaces automatically. However, you can control this mapping using the -n flag or a mapping file.

    Mapping individual files to different namespaces

    If multiple XSD files share the same targetNamespace, you can force them into different C# namespaces by appending the filename to the XML namespace using a pipe (|) symbol:

    xscgen -n "|a.xsd=Example.NamespaceA" -n "|b.xsd=Example.NamespaceB" a.xsd b.xsd

    Mapping empty XML namespaces

    To provide a namespace for elements with no XML namespace, use:

    xscgen -n Example example.xsd
    # or
    xscgen -n =Example example.xsd

    Using a mapping file

    Create a text file with one mapping per line. Lines starting with # are ignored.

    Format: XML_NAMESPACE = C#_NAMESPACE [optional file name]

    Example file content:

    # My Mappings
    http://example.com = Example.NamespaceA a.xsd
    http://example.com = Example.NamespaceB b.xsd
    Empty
    # or alternatively
    = Empty

    Use this file with the --nf, --namespaceFile=VALUE option.

    xscgen --nf mappings.txt a.xsd b.xsd
  5. Install XmlSchemaClassGenerator

    master

    You can install XmlSchemaClassGenerator in several ways depending on your workflow:

    • As a .NET Core CLI tool: Install the dotnet-xscgen NuGet package.
    • As a Console Application: Use the binaries provided in the tools folder of the XmlSchemaClassGenerator.Console NuGet package.
    • As a Library: Use the XmlSchemaClassGenerator-beta NuGet package for programmatic usage in C#.
    • Manual Download: Download binary zips from the GitHub releases page.
    dotnet tool install --global dotnet-xscgen
  6. Configure integer type mapping

    master

    The generator approximates XML xs:integer types to the closest .NET type. You can override this behavior using the --integer=TYPE option.

    Supported Types: sb[yte], sh[ort], i[nt], l[ong], ni[nt], b[yte], us[hort], ui[nt], ul[ong], nui[nt], or decimal.

    Fallback Mode: If you use the --fb, --fallback flag, the specified integer type will only be used if the generator cannot automatically deduce a more appropriate type based on the schema's minInclusive and maxInclusive restrictions.

    xscgen --integer=long example.xsd
  7. Use XmlSchemaClassGenerator as a C# library

    master

    You can integrate the generator directly into your C# code using the XmlSchemaClassGenerator-beta NuGet package.

    var generator = new Generator
    {
        OutputFolder = outputFolder,
        Log = s => Console.Out.WriteLine(s),
        GenerateNullables = true,
        NamespaceProvider = new Dictionary<NamespaceKey, string> 
        { 
            { new NamespaceKey("http://wadl.dev.java.net/2009/02"), "Wadl" } 
        }
        .ToNamespaceProvider(new GeneratorConfiguration { NamespacePrefix = "Wadl" }.NamespaceProvider.GenerateNamespace)
    };
    
    generator.Generate(files);

    To provide a custom NamespaceProvider, you can instantiate it and define the GenerateNamespace function:

    var generator = new Generator
    {
        NamespaceProvider = new NamespaceProvider
        {
            GenerateNamespace = key => /* your custom logic */
        }
    };
    var generator = new Generator
    {
        OutputFolder = outputFolder,
        Log = s => Console.Out.WriteLine(s),
        GenerateNullables = true,
        NamespaceProvider = new Dictionary<NamespaceKey, string> 
        { 
            { new NamespaceKey("http://wadl.dev.java.net/2009/02"), "Wadl" } 
        }
        .ToNamespaceProvider(new GeneratorConfiguration { NamespacePrefix = "Wadl" }.NamespaceProvider.GenerateNamespace)
    };
    
    generator.Generate(files);
  8. Reference: Collection Type Configuration

    master

    When generating collection properties, you can specify the collection type and its implementation using the following options. Note that values must be in the format accepted by Type.GetType() (e.g., System.Collections.Generic.List1`).

    Options:

    • --ct, --collectionType=VALUE: The type of the collection (default: System.Collections.ObjectModel.Collection1).
    • --cit, --collectionImplementationType=VALUE: The implementation type of the collection (default: null).
    • --csm, --collectionSettersMode=VALUE: Controls how the setter is generated.
      • Options: Private, Public, PublicWithoutConstructorInitialization, Init, InitWithoutConstructorInitialization (default: Private).
    --ct System.Collections.Generic.List`1
    --cit System.Collections.Generic.List`1
    --csm Init
  9. Reference: Restriction Metadata Attributes

    master

    When --emitMetadataAttributes is enabled, the generator produces custom attributes for specific XML schema facets. These attributes are placed in the namespace defined by --metadataNamespace (default: XmlSchemaClassGenerator.Metadata).

    XML Schema facetGenerated attribute
    xs:fractionDigitsFractionDigitsAttribute
    xs:maxLength / xs:minLength (on repeating elements)CollectionItemStringLengthAttribute
    // Example of generated metadata attribute usage
    [FractionDigits(2)]
    public decimal Price { get; set; }
  10. Use XmlSchemaClassGenerator via CLI

    master

    The xscgen command generates C# classes from XML Schema (.xsd) files. It supports globs and URLs for input files.

    Basic Syntax: xscgen [OPTIONS]+ xsdFile...

    Key Options:

    • -n, --namespace=VALUE: Map an XML namespace to a C# namespace using XML_NAMESPACE=C#_NAMESPACE.
    • -o, --output=FOLDER: Specify the output directory for .cs files.
    • -t, --interface: Generate interfaces for groups and attribute groups (enabled by default).
    • --sf, --separateFiles: Generate one file per class (disabled by default).
    • --nullable: Generate nullable adapter properties for optional elements/attributes (e.g., IdValue and IdSpecified).
    • --tns, --typeNameSubstitute=VALUE: Substitute generated names using the format {kindId}:{generatedName}={substituteName}.

    Note: To disable an option, append a dash to its name (e.g., --interface-).

    xscgen -n "http://example.com=Example.Namespace" -o ./output content/*.xsd