XSD 工具在 .NET8 中 – 第 9 部分 – LiquidXMLObjects – 简单
.NET8 环境中可用的 XSD 工具实用指南。
1 在 .NET8 中进行 XML 和 XSD 相关工作
我最近在 .NET8 环境中进行了一些与 XML 和 XSD 处理相关的工作,并创建了几个概念验证应用程序来评估可用的工具。这些文章是我原型设计工作的结果。
1.1 使用/测试的工具列表
以下是使用/测试的工具
- Visual Studio 2022
- XSD.EXE(微软许可,VS2022 的一部分)
- XmlSchemaClassGenerator (开源/免费软件)
- LinqToXsdCore (开源/免费软件)
- Liquid XML Objects (商业许可)
1.2 本系列文章
由于技术原因,我将把这篇文章组织成几篇文章
- .NET8 中的 XSD 工具 – 第 1 部分 – VS2022
- .NET8 中的 XSD 工具 – 第 2 部分 – C# 验证
- .NET8 中的 XSD 工具 – 第 3 部分 – XsdExe – 简单
- .NET8 中的 XSD 工具 – 第 4 部分 – XsdExe - 高级
- .NET8 中的 XSD 工具 – 第 5 部分 – XmlSchemaClassGenerator – 简单
- .NET8 中的 XSD 工具 – 第 6 部分 – XmlSchemaClassGenerator – 高级
- .NET8 中的 XSD 工具 – 第 7 部分 – LinqToXsdCore – 简单
- .NET8 中的 XSD 工具 – 第 8 部分 – LinqToXsdCore – 高级
- .NET8 中的 XSD 工具 – 第 9 部分 – LiquidXMLObjects – 简单
- .NET8 中的 XSD 工具 – 第 10 部分 – LiquidXMLObjects – 高级
2 更多关于 XML 和 XSD 规则的理论
这里有更多关于 XML 和 XSD 规则的理论。
2.1 可选的 Xml-Element 和 Xml-Attribute
可选:XML 中不需要存在。
对于 XSD Schema 元素
可选:minOccurs="0" 属性 ->要将 Schema 元素设置为可选,请包含 minOccurs="0" 属性。
3 XML 和 XSD 的示例
以下是我为测试目的创建的一些示例 XML 和 XSD。
3.1 简单情况
请注意,此示例 XML/XSD 包含一个 可选的 Xml-Element。有关更多详细信息,请阅读其中的注释。
<?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>
<?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>
</SmallCompany>
4 使用 LiquidXMLObjects 工具创建 C# 类
本文重点介绍 LiquidXMLObjects 工具如何从 XSD 文件生成 C# 类。
以下是该工具的基本信息。
Tool name: ============================
Liquid XML Objects
License============================
2 licenses:
1) Free Community Edition: Home Users and Students, XML Schema (size limited)
2) Commercial Product, Developer Bundle (Installed) $770.94 (perpetual license)
Where to get it============================
https://www.liquid-technologies.com/xml-objects
Install Instructions====================================
-a free trial which will expire 15 days after activation, after this time the product will continue to operate as the Free Community Edition.
Version============================
Liquid Studio - Community Edition 20.7.14.13112
Help============================
https://www.liquid-technologies.com/Reference/XmlDataBinding/xml-objects-introduction.html
====================================================
Usage Examples===================
Instructions to generate C# class
Using GUI - context right click on .xsd file
====================================
4.1 GUI
这个商业产品有一个令人印象深刻的 GUI 来发出命令。以下是 C# 类的生成方式。
您可以使用右键菜单调用 C# 类生成
这是我为 C# 代码生成设置的选项。
5 生成的 C# 类
这是上述工具根据上面提供的 XSD SmallCompany.xsd 生成的 C# 代码。
///////////////////////////////////////////////////////////////////////////
// Liquid XML Objects GENERATED CODE - DO NOT MODIFY //
// https://www.liquid-technologies.com/xml-objects //
//=======================================================================//
// Dependencies //
// Nuget : LiquidTechnologies.XmlObjects.Runtime //
// : MUST BE VERSION 20.7.14 //
//=======================================================================//
// Online Help //
// https://www.liquid-technologies.com/xml-objects-quick-start-guide //
//=======================================================================//
// Licensing Information //
// https://www.liquid-technologies.com/eula //
///////////////////////////////////////////////////////////////////////////
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Numerics;
using LiquidTechnologies.XmlObjects;
using LiquidTechnologies.XmlObjects.Attribution;
// ------------------------------------------------------
// | Settings |
// ------------------------------------------------------
// GenerateCommonBaseClass = False
// GenerateUnprocessedNodeHandlers = False
// RaiseChangeEvents = False
// CollectionNaming = Pluralize
// Language = CS
// OutputNamespace = XsdExample_Ver4.XSD1
// WriteDefaultValuesForOptionalAttributes = True
// WriteDefaultValuesForOptionalElements = True
// MixedContentHandling = TreatAsAny
// GenerationModel = Simple
// *WARNING* this simplified model that is very easy to work with
// but may cause the XML to be produced without regard for element
// cardinality or order. Where very high compliance with the XML Schema
// standard is required use GenerationModelType.Conformant
// XSD Schema Files
// C:\TmpXSD\XsdExample_Ver4\Example01\XSD1\SmallCompany.xsd
namespace XsdExample_Ver4.XSD1
{
#region Global Settings
/// <summary>Contains library level properties, and ensures the version of the runtime used matches the version used to generate it.</summary>
[LxRuntimeRequirements("20.7.14.13112", "Free Community Edition", "M9WDQLWDQNEEVNLX", LiquidTechnologies.XmlObjects.LicenseTermsType.CommunityEdition)]
public partial class LxRuntimeRequirementsWritten
{
}
#endregion
}
namespace XsdExample_Ver4.XSD1.Xs
{
#region Complex Types
/// <summary>A class representing the root XSD complexType anyType@http://www.w3.org/2001/XMLSchema</summary>
[LxSimpleComplexTypeDefinition("anyType", "http://www.w3.org/2001/XMLSchema")]
public partial class AnyTypeCt : XElement
{
/// <summary>Constructor : create a <see cref="AnyTypeCt" /> element <anyType xmlns='http://www.w3.org/2001/XMLSchema'></summary>
public AnyTypeCt() : base(XName.Get("anyType", "http://www.w3.org/2001/XMLSchema")) { }
}
#endregion
}
namespace XsdExample_Ver4.XSD1.Tns
{
#region Elements
/// <summary>A class representing the root XSD element SmallCompany@https://markpelf.com/SmallCompany.xsd</summary>
[LxSimpleElementDefinition("SmallCompany", "https://markpelf.com/SmallCompany.xsd", ElementScopeType.GlobalElement)]
public partial class SmallCompanyElm
{
/// <summary>A <see cref="System.String" />, Required : should not be set to null</summary>
[LxElementValue(0, "CompanyName", "https://markpelf.com/SmallCompany.xsd", LxValueType.Value, XsdType.XsdString, MinOccurs = 1, MaxOccurs = 1)]
public System.String CompanyName { get; set; } = "";
/// <summary>A collection of <see cref="XsdExample_Ver4.XSD1.Tns.SmallCompanyElm.EmployeeElm" /></summary>
[LxElementRef(1, MinOccurs = 0, MaxOccurs = LxConstants.Unbounded)]
public List<XsdExample_Ver4.XSD1.Tns.SmallCompanyElm.EmployeeElm> Employees { get; } = new List<XsdExample_Ver4.XSD1.Tns.SmallCompanyElm.EmployeeElm>();
/// <summary>A collection of <see cref="XsdExample_Ver4.XSD1.Tns.SmallCompanyElm.InfoDataElm" /></summary>
[LxElementRef(2, MinOccurs = 0, MaxOccurs = LxConstants.Unbounded)]
public List<XsdExample_Ver4.XSD1.Tns.SmallCompanyElm.InfoDataElm> InfoData { get; } = new List<XsdExample_Ver4.XSD1.Tns.SmallCompanyElm.InfoDataElm>();
/// <summary>Represent the inline xs:element Employee@https://markpelf.com/SmallCompany.xsd.</summary>
[LxSimpleElementDefinition("Employee", "https://markpelf.com/SmallCompany.xsd", ElementScopeType.InlineElement)]
public partial class EmployeeElm
{
/// <summary>A <see cref="System.String" />, Required : should not be set to null</summary>
[LxElementValue(0, "Name_String_NO", "https://markpelf.com/SmallCompany.xsd", LxValueType.Value, XsdType.XsdString, MinOccurs = 1, MaxOccurs = 1)]
public System.String Name_String_NO { get; set; } = "";
/// <summary>A <see cref="System.String" />, Optional : null when not set</summary>
[LxElementValue(1, "City_String_O", "https://markpelf.com/SmallCompany.xsd", LxValueType.Value, XsdType.XsdString, MinOccurs = 0, MaxOccurs = 1)]
public System.String? City_String_O { get; set; }
}
/// <summary>Represent the inline xs:element InfoData@https://markpelf.com/SmallCompany.xsd.</summary>
[LxSimpleElementDefinition("InfoData", "https://markpelf.com/SmallCompany.xsd", ElementScopeType.InlineElement)]
public partial class InfoDataElm
{
/// <summary>A <see cref="System.Int32" />, Required</summary>
[LxElementValue(0, "Id_Int_NO", "https://markpelf.com/SmallCompany.xsd", LxValueType.Value, XsdType.XsdInt, MinOccurs = 1, MaxOccurs = 1)]
public System.Int32 Id_Int_NO { get; set; }
/// <summary>A nullable <see cref="System.Int32" />, Optional : null when not set</summary>
[LxElementValue(1, "Quantity_Int_O", "https://markpelf.com/SmallCompany.xsd", LxValueType.Value, XsdType.XsdInt, MinOccurs = 0, MaxOccurs = 1)]
public System.Int32? Quantity_Int_O { get; set; }
}
}
#endregion
}
这是类的类图。
6 可选 Xml-Elements 的两种 C# API 样式
在生成的 C# 代码中,有两种方法/样式可以标记可选 Xml-Element 的存在。
- 第一种是 bool_flag_style – 使用布尔标志来指示可选 Xml-Element 的存在,flag=false 表示 Xml-Element 不存在。
例如,对于一个 Xml-Element ElemA,如果存在,其值将是整数,您将在生成的 C# 代码中得到两个变量“bool ElemA_flag, int ElemA_value”。您需要通过首先检查标志 ElemA_flag 来检查元素 ElemA 是否存在;然后,如果为 true,则获取 ElemA_value 的值。如果您不先检查标志 ElemA_flag,而是直接获取 ElemA_value 的值,您可能会得到默认值零 (0),而您无法区分这仅仅是 C# 变量的默认值(因为它始终存在),但 Xml-Element 不存在,还是该元素存在并且其值就是零 (0)。 - 第二个是 nullable_type_style – 使用可空类型来指示 Xml 元素是否存在,值为 null 表示 Xml 元素不存在。
例如,对于一个 Xml-Element ElemA,如果存在,其值将是整数,您将在生成的 C# 代码中得到一个变量“int? ElemA_nullableValue”。您需要通过首先检查 ElemA_nullableValue 是否为 null 来检查元素 ElemA 是否存在;然后,如果它不为 null,则表示该元素存在,您可以获取 ElemA_nullableValue 的 int 值。
7 示例 C# 应用程序
下面是一个使用上述生成的 C# 类来加载和处理上面提供的 XML SmallCompanyAAA.xml 的 C# 代码示例。
public static void ProcessVer4_Process1(
string? filePath,
Microsoft.Extensions.Logging.ILogger? logger)
{
try
{
logger?.LogInformation(
"+++ProcessVer4_Process1-Start++++++++++++++++++");
logger?.LogInformation("filePath:" + filePath);
LxSerializer<XsdExample_Ver4.XSD1.Tns.SmallCompanyElm> serializer =
new LxSerializer<XsdExample_Ver4.XSD1.Tns.SmallCompanyElm>();
TextReader textReader = File.OpenText(filePath ?? String.Empty);
LxReaderSettings readerSettings = new LxReaderSettings();
XsdExample_Ver4.XSD1.Tns.SmallCompanyElm? xmlObject =
serializer.Deserialize(textReader, readerSettings);
if (xmlObject != null)
{
logger?.LogInformation("CompanyName:" + xmlObject.CompanyName);
foreach(XsdExample_Ver4.XSD1.Tns.SmallCompanyElm.EmployeeElm item in xmlObject.Employees)
{
logger?.LogInformation("------------" );
logger?.LogInformation("Name_String_NO:" + item.Name_String_NO);
logger?.LogInformation("City_String_O:" + (item.City_String_O ?? "null") );
}
foreach (XsdExample_Ver4.XSD1.Tns.SmallCompanyElm.InfoDataElm item in xmlObject.InfoData)
{
logger?.LogInformation("------------");
logger?.LogInformation("Id_Int_NO:" + item.Id_Int_NO.ToString());
logger?.LogInformation("Quantity_Int_O:" + (item.Quantity_Int_O?.ToString() ?? "null"));
}
}
else
{
logger?.LogError("xmlObject == null");
}
logger?.LogInformation(
"+++ProcessVer4_Process1-End++++++++++++++++++");
}
catch (Exception ex)
{
string methodName =
$"Type: {System.Reflection.MethodBase.GetCurrentMethod()?.DeclaringType?.FullName}, " +
$"Method: ProcessVer4_Process1; ";
logger?.LogError(ex, methodName);
}
}
这是执行日志。
+++ProcessVer4_Process1-Start++++++++++++++++++
filePath:C:\TmpXSD\XsdExample_Ver4\Example01\bin\Debug\net8.0\XmlFiles\SmallCompanyAAA.xml
CompanyName:SmallCompanyAAA
------------
Name_String_NO:Mark
City_String_O:Belgrade
------------
Name_String_NO:John
City_String_O:null
------------
Id_Int_NO:11
Quantity_Int_O:123
------------
Id_Int_NO:22
Quantity_Int_O:null
+++ProcessVer4_Process1-End++++++++++++++++++
8 分析
此工具使用“nullable_type_style”方法/样式来标记生成 C# 代码中可选的 Xml-Element 的存在。
- Quantity_Int_O – 是 int? 类型,含义是
a) null - 表示它不存在。
b) int – 存在并有值。
9 结论
这个 LiquidXMLObjects 工具非常有趣,但需要商业许可。在我测试过的代码生成的质量看起来很扎实。对于那些希望使用nullable_type_style API 的用户来说,它可能非常有价值,这通常是处理可选 Xml-Element 的更现代的方法。
10 参考文献
[1] XML 架构
https://w3schools.org.cn/xml/xml_schema.asp
[2] 可选和非必需的区别
https://www.infopathdev.com/blogs/greg/archive/2004/09/16/The-Difference-Between-Optional-and-Not-Required.aspx
[3] nillable 和 minOccurs XSD 元素属性
https://stackoverflow.com/questions/1903062/nillable-and-minoccurs-xsd-element-attributes
[21] .NET8 中的 XSD 工具 – 第 1 部分 – VS2022
https://codeproject.org.cn/Articles/5388391/XSD-Tools-in-NET8-Part1-VS2022
[22] XSD 工具在 .NET8 中 – 第 2 部分 – C# 验证
https://codeproject.org.cn/Articles/5388393/XSD-Tools-in-NET8-Part2-Csharp-validation
[23] XSD 工具在 .NET8 中 – 第 3 部分 – XsdExe – 简单
https://codeproject.org.cn/Articles/5388396/XSD-Tools-in-NET8-Part3-XsdExe-Simple
[24] XSD 工具在 .NET8 中 – 第 4 部分 – XsdExe – 高级
https://codeproject.org.cn/Articles/5388483/XSD-Tools-in-NET8-Part4-XsdExe-Advanced
[25] XSD 工具在 .NET8 中 – 第 5 部分 – XmlSchemaClassGenerator – 简单
https://codeproject.org.cn/Articles/5388548/XSD-Tools-in-NET8-Part5-XmlSchemaClassGenerator-Si
[26] XSD 工具在 .NET8 中 – 第 6 部分 – XmlSchemaClassGenerator – 高级
https://codeproject.org.cn/Articles/5388549/XSD-Tools-in-NET8-Part6-XmlSchemaClassGenerator-Ad
[27] XSD 工具在 .NET8 中 – 第 7 部分 – LinqToXsdCore – 简单
https://codeproject.org.cn/Articles/5388628/XSD-Tools-in-NET8-Part7-LinqToXsdCore-Simple
[28] XSD 工具在 .NET8 中 – 第 8 部分 – LinqToXsdCore – 高级
https://codeproject.org.cn/Articles/5388629/XSD-Tools-in-NET8-Part8-LinqToXsdCore-Advanced
[29] XSD 工具在 .NET8 中 – 第 9 部分 – LiquidXMLObjects – 简单
https://codeproject.org.cn/Articles/5388683/XSD-Tools-in-NET8-Part9-LiquidXMLObjects-Simple
[30] XSD 工具在 .NET8 中 – 第 10 部分 – LiquidXMLObjects – 高级
https://codeproject.org.cn/Articles/5388684/XSD-Tools-in-NET8-Part10-LiquidXMLObjects-Advanced