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).
1 Doing XML and XSD related work in .NET8
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