XSD Tools in .NET8 – Part2 – C# validation

Mark PelfMark Pelf
4 min read

XSD Tools in .NET8 – Part2 – C# validation

A practical guide to XSD tools available in .NET8 environment.

Abstract: A practical guide to XML and XSD tools available in .NET8 environment, focusing on generating and using C# classes to process some XML valid for some given XSD (technology as of September 2024).

I was recently doing some work related to XML and XSD processing in .NET8 environment and created several proof-of-concept applications to evaluate the tools available. These articles are the result of my prototyping work.

1.1 List of tools used/tested

Here are the tools used/tested:

  • Visual Studio 2022
  • XSD.EXE (Microsoft license, part of VS2022)
  • XmlSchemaClassGenerator (Open Source/Freeware)
  • LinqToXsdCore (Open Source/Freeware)
  • Liquid XML Objects (Commercial license)

1.2 Articles in this series

For technical reasons, I will organize this text into several articles:

  • XSD Tools in .NET8 – Part1 – VS2022
  • XSD Tools in .NET8 – Part2 – C# validation
  • XSD Tools in .NET8 – Part3 – XsdExe – Simple
  • XSD Tools in .NET8 – Part4 – XsdExe - Advanced
  • XSD Tools in .NET8 – Part5 – XmlSchemaClassGenerator – Simple
  • XSD Tools in .NET8 – Part6 – XmlSchemaClassGenerator – Advanced
  • XSD Tools in .NET8 – Part7 – LinqToXsdCore – Simple
  • XSD Tools in .NET8 – Part8 – LinqToXsdCore – Advanced
  • XSD Tools in .NET8 – Part9 – LiquidXMLObjects – Simple
  • XSD Tools in .NET8 – Part10 – LiquidXMLObjects – Advanced

2 Examples of XML and XSD

Some sample XML-s and XSD-s I created for test purposes.

2.1 Simple case

<?xml version="1.0" encoding="utf-8"?>
<!--SmallCompany.xsd++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<xs:schema attributeFormDefault="unqualified" 
           elementFormDefault="qualified" 
           targetNamespace="https://markpelf.com/SmallCompany.xsd" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="SmallCompany">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="CompanyName" type="xs:string" />
                <xs:element maxOccurs="unbounded" name="Employee">
                    <xs:complexType>
                        <xs:sequence>
                            <!--Name_String_NO is String NotOptional-->
                            <xs:element name="Name_String_NO" type="xs:string" />
                            <!--City_String_O is String Optional-->
                            <xs:element minOccurs="0" name="City_String_O" type="xs:string" />
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:element maxOccurs="unbounded" name="InfoData">
                    <xs:complexType>
                        <xs:sequence>
                            <!--Id_Int_NO is Int NotOptional-->
                            <xs:element name="Id_Int_NO" type="xs:int" />
                            <!--Quantity_Int_O is Int Optional-->
                            <xs:element minOccurs="0" name="Quantity_Int_O" type="xs:int" />
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

Valid XML

<?xml version="1.0" encoding="utf-8"?>
<!--SmallCompany.xsd++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
<xs:schema attributeFormDefault="unqualified" 
           elementFormDefault="qualified" 
           targetNamespace="https://markpelf.com/SmallCompany.xsd" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="SmallCompany">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="CompanyName" type="xs:string" />
                <xs:element maxOccurs="unbounded" name="Employee">
                    <xs:complexType>
                        <xs:sequence>
                            <!--Name_String_NO is String NotOptional-->
                            <xs:element name="Name_String_NO" type="xs:string" />
                            <!--City_String_O is String Optional-->
                            <xs:element minOccurs="0" name="City_String_O" type="xs:string" />
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:element maxOccurs="unbounded" name="InfoData">
                    <xs:complexType>
                        <xs:sequence>
                            <!--Id_Int_NO is Int NotOptional-->
                            <xs:element name="Id_Int_NO" type="xs:int" />
                            <!--Quantity_Int_O is Int Optional-->
                            <xs:element minOccurs="0" name="Quantity_Int_O" type="xs:int" />
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

Invalid XML

<?xml version="1.0" encoding="utf-8"?>
<!--SmallCompanyAAA.xml+++++++++++++++++++++++++++++++++++++++++++++++-->
<SmallCompany xmlns="https://markpelf.com/SmallCompany.xsd">
    <CompanyName>SmallCompanyAAA</CompanyName>
    <Employee>
        <Name_String_NO>Mark</Name_String_NO>
        <City_String_O>Belgrade</City_String_O>
    </Employee>
    <Employee>
        <Name_String_NO>John</Name_String_NO>
    </Employee>
    <InfoData>
        <Id_Int_NO>11</Id_Int_NO>
        <Quantity_Int_O>123</Quantity_Int_O>
    </InfoData>
    <InfoData>
        <Id_Int_NO>22</Id_Int_NO>
    </InfoData>
    <Offending_Element>
        Bla_Bla
    </Offending_Element>
</SmallCompany>

2.2 Advanced case

Same as in the previous article.

3 Validation in C

Writing C# code to “validate XML for some XSD” is pretty basic, but still the right starting point.

3.1 C# code

Here is a sample code to do XML validation in C# for some XSD.

public static bool ValidateXmlForXsd(
    Microsoft.Extensions.Logging.ILogger? _logger, 
    string xmlPath, string xsdPath)
{
    bool isValid=false;

    XmlDocument xml = new XmlDocument();
    xml.Load(xmlPath);

    xml.Schemas.Add(null, xsdPath);

    try
    {
        xml.Validate(null);
        isValid = true;
    }
    catch (XmlSchemaValidationException ex)
    {
        string text1 = $"Validation FAILED for: xmlPath={xmlPath}" +
            $" and xsdPath={xsdPath} .Validation Error: " +
            ex.Message;
        _logger?.LogInformation(text1);
        isValid = false;
    }

    if (isValid)
    {
        string text1 = $"Validation SUCCESS for: xmlPath={xmlPath}" +
            $" and  xsdPath={xsdPath}";
        _logger?.LogInformation(text1);
    }
    return isValid;
}

3.2 Success case log

Here is the log of the validation success case.

 XsdExample01-Start------------
 xmlFile11_FullPath: C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\SmallCompanyAAA.xml
 xsdFile1_FullPath: C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\SmallCompany.xsd
 xmlFile21_FullPath: C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\BigCompanyMMM.xml
 xsdFile2_FullPath: C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\BigCompany.xsd
 Validation SUCCESS for: 
 xmlPath=C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\SmallCompanyAAA.xml
 and  xsdPath=C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\SmallCompany.xsd
 Validation SUCCESS for: 
 xmlPath=C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\BigCompanyMMM.xml 
 and  xsdPath=C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\BigCompany.xsd
 XsdExample01-End------------

3.3 Failure case log

Here is the log of the validation failure case.

 XsdExample01-Start------------
 xmlFile11_FullPath: C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\SmallCompanyAAA.xml
 xsdFile1_FullPath: C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\SmallCompany.xsd
 xmlFile21_FullPath: C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\BigCompanyMMM.xml
 xsdFile2_FullPath: C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\BigCompany.xsd
 Validation FAILED for: 
 xmlPath=C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\SmallCompanyAAA.xml 
 and xsdPath=C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\SmallCompany.xsd .
 Validation Error: The element 'SmallCompany' in namespace 'https://markpelf.com/SmallCompany.xsd' has 
 invalid child element 'Offending_Element' in namespace 'https://markpelf.com/SmallCompany.xsd'. List 
 of possible elements expected: 'InfoData' in namespace 'https://markpelf.com/SmallCompany.xsd'.
 Validation SUCCESS for: 
 xmlPath=C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\BigCompanyMMM.xml 
 and  xsdPath=C:\TmpXSD\XsdExample_Validate\Example01\bin\Debug\net8.0\XmlFiles\BigCompany.xsd
 XsdExample01-End------------

The full example code project can be downloaded at GitHub [99].

4 References

[1] XML Schema
https://www.w3schools.com/xml/xml_schema.asp

[2] The Difference Between Optional and Not Required
https://www.infopathdev.com/blogs/greg/archive/2004/09/16/The-Difference-Between-Optional-and-Not-Required.aspx

[3] nillable and minOccurs XSD element attributes
https://stackoverflow.com/questions/1903062/nillable-and-minoccurs-xsd-element-attributes

[99] https://github.com/MarkPelf/XsdToolsInNet8

0
Subscribe to my newsletter

Read articles from Mark Pelf directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mark Pelf
Mark Pelf

A Software Engineer from Belgrade, Serbia.