65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET8 中的 XSD 工具 – 第三部分 – XsdExe- 简单

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2024 年 9 月 21 日

CPOL

4分钟阅读

viewsIcon

4927

downloadIcon

115

.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 使用 XSD.EXE 工具创建 C# 类

在本文中,我们将重点介绍使用 XSD.EXE 工具从 XSD 文件生成 C# 类。
以下是该工具的基本信息。

Tool name============================
XSD.exe

License============================ 
Microsoft, comming with Visual Studio

Where to get it=========================
C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools\x64\xsd.exe

Version==========================
Windows PowerShell > ./xsd.exe
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 4.8.9037.0]
Copyright (C) Microsoft Corporation. All rights reserved.

Help============================
Windows PowerShell > ./xsd.exe
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 4.8.9037.0]
Copyright (C) Microsoft Corporation. All rights reserved.

xsd.exe -
    Utility to generate schema or class files from given source.

xsd.exe <schema>.xsd /classes|dataset [/e:] [/l:] [/n:] [/o:] [/s] [/uri:]
xsd.exe <assembly>.dll|.exe [/outputdir:] [/type: [...]]
xsd.exe <instance>.xml [/outputdir:]
xsd.exe <schema>.xdr [/outputdir:]

     - OPTIONS -

/classes
    Generate classes for this schema. Short form is '/c'.

/dataset
    Generate sub-classed DataSet for this schema. Short form is '/d'.

/enableLinqDataSet
    Generate LINQ-enabled sub-classed Dataset for the schemas provided.  Short form is '/eld'.

/element:<element>
    Element from schema to process. Short form is '/e:'.

/fields
    Generate fields instead of properties. Short form is '/f'.

/order
    Generate explicit order identifiers on all particle members.

/enableDataBinding
    Implement INotifyPropertyChanged interface on all generated types
    to enable data binding. Short form is '/edb'.

/language:<language>
    The language to use for the generated code. Choose from 'CS', 'VB', 'JS',
    'VJS', 'CPP' or provide a fully-qualified name for a class implementing
    System.CodeDom.Compiler.CodeDomProvider. The default language
    is 'CS' (CSharp). Short form is '/l:'.

/namespace:<namespace>
    The namespace for generated class files. The default namespace
    is the global namespace. Short form is '/n:'.

/nologo
    Suppresses the banner.

/out:<directoryName>
    The output directory to create files in. The default
    is the current directory. Short form is '/o:'.

/type:<type>
    Type from assembly to generate schema for. Multiple types may be provided.
    If no types are provided, then schemas for all types in an assembly
    are generated. Short form is '/t:'.

/uri:<uri>
    Uri of elements from schema to process. Short form is '/u:'.

     - ADVANCED -

/parameters:<file>
    Read command-line options from the specified xml file. Short form is '/p:'.

     - ARGUMENTS -
<schema>.xsd       Name of a schema containing elements to import.
<assembly>.dll|exe Name of an assembly containing types to generate schema for.
<instance>.xml     Name of an xml file to infer xsd schema from.
<schema>.xdr       Name of an xdr schema to convert to xsd.
Multiple file arguments of the same type may be provided.
========================================================
Usage Examples===================                          
Instructions to generate C# class 
Windows PowerShell> ./xsd.exe SmallCompany.xsd /classes /namespace:Example1
Windows PowerShell> ./xsd.exe BigCompany.xsd /classes /namespace:Example1
======================================

 

5 生成的 C# 类

这是上述工具根据上面提供的 XSD SmallCompany.xsd 生成的 C# 代码。
这是类的完整代码。

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

// 
// This source code was auto-generated by xsd, Version=4.8.9037.0.
// 
namespace Example1 {
    using System.Xml.Serialization;
    
    
    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="https://markpelf.com/SmallCompany.xsd")]
    [System.Xml.Serialization.XmlRootAttribute(Namespace="https://markpelf.com/SmallCompany.xsd", IsNullable=false)]
    public partial class SmallCompany {
        
        private string companyNameField;
        
        private SmallCompanyEmployee[] employeeField;
        
        private SmallCompanyInfoData[] infoDataField;
        
        /// <remarks/>
        public string CompanyName {
            get {
                return this.companyNameField;
            }
            set {
                this.companyNameField = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("Employee")]
        public SmallCompanyEmployee[] Employee {
            get {
                return this.employeeField;
            }
            set {
                this.employeeField = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("InfoData")]
        public SmallCompanyInfoData[] InfoData {
            get {
                return this.infoDataField;
            }
            set {
                this.infoDataField = value;
            }
        }
    }
    
    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="https://markpelf.com/SmallCompany.xsd")]
    public partial class SmallCompanyEmployee {
        
        private string name_String_NOField;
        
        private string city_String_OField;
        
        /// <remarks/>
        public string Name_String_NO {
            get {
                return this.name_String_NOField;
            }
            set {
                this.name_String_NOField = value;
            }
        }
        
        /// <remarks/>
        public string City_String_O {
            get {
                return this.city_String_OField;
            }
            set {
                this.city_String_OField = value;
            }
        }
    }
    
    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.9037.0")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="https://markpelf.com/SmallCompany.xsd")]
    public partial class SmallCompanyInfoData {
        
        private int id_Int_NOField;
        
        private int quantity_Int_OField;
        
        private bool quantity_Int_OFieldSpecified;
        
        /// <remarks/>
        public int Id_Int_NO {
            get {
                return this.id_Int_NOField;
            }
            set {
                this.id_Int_NOField = value;
            }
        }
        
        /// <remarks/>
        public int Quantity_Int_O {
            get {
                return this.quantity_Int_OField;
            }
            set {
                this.quantity_Int_OField = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlIgnoreAttribute()]
        public bool Quantity_Int_OSpecified {
            get {
                return this.quantity_Int_OFieldSpecified;
            }
            set {
                this.quantity_Int_OFieldSpecified = value;
            }
        }
    }
}

 

这是类的类图。

 

6 可选 Xml-Elements 的两种 C# API 样式

在生成的 C# 代码中,有两种方法/样式可以标记可选 Xml-Element 的存在。

  1. 第一种是 bool_flag_style – 使用布尔标志来指示可选 Xml-Element 的存在,flag=false 表示 Xml-Element 不存在。
    例如,对于某些 Xml-Element ElemA,如果存在,其值为整数,您将在 C# 中生成两个变量“bool ElemA_flag, int ElemA_value”。您需要通过首先检查标志 ElemA_flag 来检查元素 ElemA 是否存在;如果为真,则获取 ElemA_value 的值。如果您不先检查标志 ElemA_flag,而直接获取 ElemA_value 的值,您可能会获得零 (0) 的默认 int 值,而您无法知道这只是 C# 变量的默认值(始终存在),但 Xml-Element 不存在,还是该元素存在并且实际值为零 (0)。
  2. 第二个是 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 ProcessVer1_Process1(
    string? filePath,
    Microsoft.Extensions.Logging.ILogger? logger)
{
    try
    {
        logger?.LogInformation(
            "+++ProcessVer1_Process1-Start++++++++++++++++++");
        logger?.LogInformation("filePath:" + filePath);

        XmlSerializer ser = new XmlSerializer(typeof(Example1.SmallCompany));
        TextReader textReader = File.OpenText(filePath ?? String.Empty);
        Example1.SmallCompany? xmlObject = ser.Deserialize(textReader) as Example1.SmallCompany;

        if (xmlObject != null)
        {
            logger?.LogInformation("CompanyName:" + xmlObject.CompanyName);

            foreach(Example1.SmallCompanyEmployee item in xmlObject.Employee)
            {
                logger?.LogInformation("------------" );
                logger?.LogInformation("Name_String_NO:" + item.Name_String_NO);
                logger?.LogInformation("City_String_O:" + item.City_String_O);
            }

            foreach (Example1.SmallCompanyInfoData item in xmlObject.InfoData)
            {
                logger?.LogInformation("------------");
                logger?.LogInformation("Id_Int_NO:" + item.Id_Int_NO.ToString());
                logger?.LogInformation("Quantity_Int_OSpecified:" + item.Quantity_Int_OSpecified.ToString());
                logger?.LogInformation("Quantity_Int_O:" + item.Quantity_Int_O.ToString());
            }
        }
        else
        {
            logger?.LogError("xmlObject == null");
        }

        logger?.LogInformation(
            "+++ProcessVer1_Process1-End++++++++++++++++++");
    }
    catch (Exception ex)
    {
        string methodName =
            $"Type: {System.Reflection.MethodBase.GetCurrentMethod()?.DeclaringType?.FullName}, " +
            $"Method: ProcessVer1_Process1; ";
        logger?.LogError(ex, methodName);
    }
}

 

这是执行日志。

 +++ProcessVer1_Process1-Start++++++++++++++++++
 filePath:C:\TmpXSD\XsdExample_Ver1\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:
 ------------
 Id_Int_NO:11
 Quantity_Int_OSpecified:True
 Quantity_Int_O:123
 ------------
 Id_Int_NO:22
 Quantity_Int_OSpecified:False
 Quantity_Int_O:0
 +++ProcessVer1_Process1-End++++++++++++++++++

 

8 分析

该工具使用 **“bool_flag_style”** 方法/样式来标记已生成 C# 代码中可选 Xml-Element 的存在。

  • Xml-Element Quantity_Int_O 由 2 个 C# 变量表示
    Quantity_Int_OSpecified – 是一个 bool 类型,而
    Quantity_Int_O – 是 int 类型,含义是
    • a) Quantity_Int_OSpecified– 用于指示元素是否存在/不存在的标志
    • b) Quantity_Int_O– 如果上述标志为 true,则这是该元素的 int 值

 

9 结论

尽管使用了旧式 **bool_flag_style** API,但该工具仍为 .NET8 环境生成可用的 C# 代码,程序员只需要熟练使用生成的 C# 类即可。

 

10 参考文献

 

[1] XML 架构
https://w3schools.org.cn/xml/xml_schema.asp

[21] .NET8 中的 XSD 工具 – 第 1 部分 – VS2022
https://codeproject.org.cn/Articles/5388391/XSD-Tools-in-NET8-Part1-VS2022

[22] .NET8 中的 XSD 工具 – 第二部分 – C# 验证
https://codeproject.org.cn/Articles/5388393/XSD-Tools-in-NET8-Part2-Csharp-validation

[23] .NET8 中的 XSD 工具 – 第三部分 – XsdExe – 简单
https://codeproject.org.cn/Articles/5388396/XSD-Tools-in-NET8-Part3-XsdExe-Simple

[24] .NET8 中的 XSD 工具 – 第四部分 – XsdExe - 高级
https://codeproject.org.cn/Articles/5388483/XSD-Tools-in-NET8-Part4-XsdExe-Advanced

[25] .NET8 中的 XSD 工具 – 第五部分 – XmlSchemaClassGenerator – 简单
https://codeproject.org.cn/Articles/5388548/XSD-Tools-in-NET8-Part5-XmlSchemaClassGenerator-Si

[26] .NET8 中的 XSD 工具 – 第六部分 – XmlSchemaClassGenerator – 高级
https://codeproject.org.cn/Articles/5388549/XSD-Tools-in-NET8-Part6-XmlSchemaClassGenerator-Ad

[27] .NET8 中的 XSD 工具 – 第七部分 – LinqToXsdCore – 简单
https://codeproject.org.cn/Articles/5388628/XSD-Tools-in-NET8-Part7-LinqToXsdCore-Simple

[28] .NET8 中的 XSD 工具 – 第八部分 – LinqToXsdCore – 高级
https://codeproject.org.cn/Articles/5388629/XSD-Tools-in-NET8-Part8-LinqToXsdCore-Advanced

[29] .NET8 中的 XSD 工具 – 第九部分 – LiquidXMLObjects – 简单
https://codeproject.org.cn/Articles/5388683/XSD-Tools-in-NET8-Part9-LiquidXMLObjects-Simple

[30] .NET8 中的 XSD 工具 – 第十部分 – LiquidXMLObjects – 高级
https://codeproject.org.cn/Articles/5388684/XSD-Tools-in-NET8-Part10-LiquidXMLObjects-Advanced

 

© . All rights reserved.