如何动态根据一个业务实体类型创建XSD架构文件

开发 后端
这是正在开发的XML数据库的一个功能,我需要动态根据一个业务实体类型创建一个XSD架构文件,并使用其对最后的XML数据文件进行约束。

目前该功能仅仅是一个原型,还有待细化改进。例如在实体的成员上用一些特定的Attribute标明该成员要被保存的形态。

创建XSD架构文件***部分:业务实体类

(作为演示目的,我将所有的类型定义在一个文件里,同时每个类都只有少量简单的属性成员)

此处特别注意的是,Order这个类是很复杂的,它包含了一系列的OrderItem,而OrderItem又包含了Product对象。

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;   
  4.  
  5. namespace DataEntities  
  6. {  
  7.     public class Order  
  8.     {  
  9.         public int OrderID { get; set; }  
  10.         public string CustomerID { get; set; }  
  11.         public int EmployeeID { get; set; }  
  12.         public DateTime OrderDate { get; set; }  
  13.         public List<OrderItem> OrderItems { get; set; }   
  14.  
  15.         public override string ToString()  
  16.         {  
  17.             StringBuilder sb = new StringBuilder();  
  18.             sb.AppendFormat("\t{0}\t{1}\t{2}\t{3}", OrderID, CustomerID, EmployeeID, OrderDate);  
  19.             sb.AppendLine();  
  20.             foreach (var item in OrderItems)  
  21.             {  
  22.                 sb.AppendFormat("\t\t{0}\t{1}\t{2}\n", item.Product.ProductName, item.UnitPrice, item.Quantity);  
  23.             }  
  24.             return sb.ToString();  
  25.         }   
  26.  
  27.     }   
  28.     public class OrderItem   
  29.     {  
  30.         public int OrderId { get; set; }  
  31.         public Product Product { get; set; }  
  32.         public decimal UnitPrice { get; set; }  
  33.         public decimal Quantity { get; set; }  
  34.  
  35.     }  
  36.     public class Product   
  37.     {  
  38.         public int ProductId { get; set; }  
  39.         public string ProductName { get; set; }  
  40.  
  41.     }  

创建XSD架构文件第二部分:生成XSD的工具类(Utility.cs)

  1. using System;  
  2. using System.Xml.Linq;  
  3. using System.Collections;  
  4. using System.Xml;  
  5.  
  6. namespace XMLDatabase  
  7. {  
  8.     public class Utility  
  9.     {  
  10.         /// <summary> 
  11.         /// 使用指定类型生成一个架构文件  
  12.         /// </summary> 
  13.         /// <typeparam name="T"></typeparam> 
  14.         public static void XsdGenerate<T>(XmlWriter xw) {  
  15.             Type t = typeof(T);  
  16.  
  17.             XNamespace xn = "http://www.w3.org/2001/XMLSchema";  
  18.             XDocument doc = new XDocument(  
  19.                 new XDeclaration("1.0", "utf-8", "yes"),  
  20.                 new XElement(xn + "schema",  
  21.                     new XAttribute("elementFormDefault", "qualified"),  
  22.                     new XAttribute(XNamespace.Xmlns + "xs", "http://www.w3.org/2001/XMLSchema"),  
  23.                     new XElement(xn+"element",  
  24.                         new XAttribute("name","Table"),  
  25.                         new XAttribute("nillable","true"),  
  26.                         new XAttribute("type","Table"))  
  27.                     ));  
  28.  
  29.  
  30.             XElement tableElement = new XElement(xn + "complexType",  
  31.                 new XAttribute("name", "Table"));  
  32.  
  33.             tableElement.Add(  
  34.                 new XElement(xn + "sequence",  
  35.                     new XElement(xn + "element",  
  36.                         new XAttribute("minOccurs", "0"),  
  37.                         new XAttribute("maxOccurs", "unbounded"),  
  38.                         new XAttribute("name","Row"),  
  39.                         new XAttribute("type",t.Name)  
  40.                         )),  
  41.                 new XElement(xn + "attribute",  
  42.                     new XAttribute("name", "CreateTime"),  
  43.                     new XAttribute("type", "xs:string"))  
  44.                         );  
  45.  
  46.             doc.Root.Add(tableElement);  
  47.  
  48.             CreateComplexType(t, doc.Root);  
  49.             doc.Save(xw);  
  50.  
  51.         }  
  52.  
  53.  
  54.         private static void CreateComplexType(Type t,XElement root) {  
  55.  
  56.             XNamespace xn = root.GetNamespaceOfPrefix("xs");  
  57.             XElement temp = new XElement(  
  58.                 xn + "complexType",  
  59.                 new XAttribute("name", t.Name));  
  60.             #region 循环所有属性  
  61.  
  62.             foreach (var p in t.GetProperties())//循环所有属性  
  63.             {  
  64.                 Type ppType = p.PropertyType;  
  65.                 string fullType = pType.FullName;  
  66.  
  67.                 //这里仍然是分几种情况  
  68.                 if (!GeneralType.Contains(fullType))  
  69.                 {  
  70.  
  71.                     var seqelement = temp.Element(xn + "sequence");  
  72.                     if (seqelement == null)  
  73.                     {  
  74.                         seqelement = new XElement(xn + "sequence");  
  75.                         temp.AddFirst(seqelement);  
  76.                     }  
  77.  
  78.                     if (pType.IsEnum)//如果是枚举  
  79.                     {  
  80.                         seqelement.Add(  
  81.                             new XElement(  
  82.                                 xn + "element",  
  83.                                 new XAttribute("minOccurs", "0"),  
  84.                                 new XAttribute("maxOccurs", "1"),  
  85.                                 new XAttribute("name", p.Name),  
  86.                                 new XAttribute("type", pType.Name)));  
  87.  
  88.                         XElement enumElement = new XElement(  
  89.                             xn + "complexType",  
  90.                             new XAttribute("name", pType.Name),  
  91.                             new XElement(xn + "attribute",  
  92.                                 new XAttribute("name", "Enum"),  
  93.                                 new XAttribute("type", "xs:string")));  
  94.                         root.Add(enumElement);  
  95.  
  96.                     }  
  97.                     else if (pType.GetInterface(typeof(IList).FullName) != null && pType.IsGenericType)  
  98.                         //如果是集合,并且是泛型集合  
  99.                     {  
  100.  
  101.                         Type itemType = pType.GetGenericArguments()[0];  
  102.                         seqelement.Add(  
  103.                             new XElement(  
  104.                                 xn + "element",  
  105.                                 new XAttribute("minOccurs", "0"),  
  106.                                 new XAttribute("maxOccurs", "1"),  
  107.                                 new XAttribute("name", p.Name),  
  108.                                 new XAttribute("type", "ArrayOf"+p.Name)));  
  109.  
  110.                         XElement arrayElement = new XElement(  
  111.                             xn + "complexType",  
  112.                             new XAttribute("name", "ArrayOf" + p.Name),  
  113.                             new XElement(xn + "sequence",  
  114.                                 new XElement(xn + "element",  
  115.                                     new XAttribute("minOccurs", "0"),  
  116.                                     new XAttribute("maxOccurs", "unbounded"),  
  117.                                     new XAttribute("name", itemType.Name),  
  118.                                     new XAttribute("type", itemType.Name))));  
  119.  
  120.                         root.Add(arrayElement);  
  121.  
  122.                         CreateComplexType(itemType, root);  
  123.  
  124.                     }  
  125.                     else if (pType.IsClass || pType.IsValueType)  
  126.                     {  
  127.                         seqelement.Add(  
  128.                             new XElement(  
  129.                                 xn + "element",  
  130.                                 new XAttribute("minOccurs", "0"),  
  131.                                 new XAttribute("maxOccurs", "1"),  
  132.                                 new XAttribute("name", p.Name),  
  133.                                 new XAttribute("type", pType.Name)));  
  134.  
  135.                         CreateComplexType(pType, root);  
  136.                     }  
  137.                 }  
  138.                 else  
  139.                 {  
  140.                     //这种情况最简单,属性为标准内置类型,直接作为元素的Attribute即可  
  141.                     temp.Add(  
  142.                         new XElement(xn + "attribute",  
  143.                             new XAttribute("name", p.Name),  
  144.                             new XAttribute("type", GeneralType.ConvertXSDType(pType.FullName))));  
  145.  
  146.                 }  
  147.  
  148.             }  
  149.             #endregion  
  150.  
  151.             temp.Add(new XElement(xn + "attribute",  
  152.                 new XAttribute("name", "TypeName"),  
  153.                 new XAttribute("type", "xs:string")));  
  154.  
  155.             root.Add(temp);  
  156.         }  
  157.  
  158.     }  

创建XSD架构文件第三部分:辅助类型(GeneralType.cs).

这个类型中有一个方法可以将业务实体类型成员属性的类型转换为XSD中 的类型。

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4.  
  5. namespace XMLDatabase  
  6. {  
  7.     public class GeneralType  
  8.     {  
  9.         private static readonly List<string> generalTypes = new List<string>()  
  10.         {  
  11.             "System.Byte",//typeof(byte).FullName,  
  12.             "System.SByte",//typeof(sbyte).FullName,  
  13.             "System.Int16",//typeof(short).FullName,  
  14.             "System.UInt16",//typeof(ushort).FullName,  
  15.             "System.Int32",//typeof(int).FullName,  
  16.             "System.UInt32",//typeof(uint).FullName,  
  17.             "System.Int64",//typeof(long).FullName,  
  18.             "System.UInt64",//typeof(ulong).FullName,  
  19.             "System.Double",//typeof(double).FullName,  
  20.             "System.Decimal",//typeof(decimal).FullName,  
  21.             "System.Single",//typeof(float).FullName,  
  22.             "System.Char",//typeof(char).FullName,  
  23.             "System.Boolean",//typeof(bool).FullName,  
  24.             "System.String",//typeof(string).FullName,  
  25.             "System.DateTime"//typeof(DateTime).FullName  
  26.         };  
  27.  
  28.  
  29.         /// <summary> 
  30.         /// 判断当前给定类型是否为默认的数据类型  
  31.         /// </summary> 
  32.         /// <param name="fullType"></param> 
  33.         /// <returns></returns> 
  34.         public static bool Contains(string fullType)  
  35.         {  
  36.             return generalTypes.Contains(fullType);  
  37.         }  
  38.  
  39.  
  40.         public static string ConvertXSDType(string fullType)  
  41.         {  
  42.             switch (fullType)  
  43.             {  
  44.                 case "System.String":  
  45.                     return "xs:string";  
  46.                 case "System.Int32":  
  47.                     return "xs:int";  
  48.                 case "System.DateTime":  
  49.                     return "xs:dateTime";  
  50.                 case "System.Boolean":  
  51.                     return "xs:boolean";  
  52.                 case "System.Single":  
  53.                     return "xs:float";  
  54.                 case "System.Byte":  
  55.                     return "xs:byte";  
  56.                 case "System.SByte":  
  57.                     return "xs:unsignedByte";  
  58.                 case "System.Int16":  
  59.                     return "xs:short";  
  60.                 case "System.UInt16":  
  61.                     return "xs:unsignedShort";  
  62.                 case "System.UInt32":  
  63.                     return "xs:unsignedInt";  
  64.                 case "System.Int64":  
  65.                     return "xs:long";  
  66.                 case "System.UInt64":  
  67.                     return "xs:unsignedLong";  
  68.                 case "System.Double":  
  69.                     return "xs:double";  
  70.                 case "System.Decimal":  
  71.                     return "xs:decimal";  
  72.  
  73.                 default:  
  74.                     break;  
  75.             }  
  76.  
  77.             return string.Empty;  
  78.         }  
  79.           
  80.     }  

创建XSD架构文件第四部分:单元测试

  1. /// <summary> 
  2. ///XsdGenerate 的测试  
  3. ///</summary> 
  4. public void XsdGenerateTestHelper<T>()  
  5. {  
  6.     XmlWriter xw = XmlWriter.Create("Order.xsd"); // TODO: 初始化为适当的值  
  7.     Utility.XsdGenerate<Order>(xw);  
  8.  
  9.     xw.Close();  

创建XSD架构文件第五部分: 生成的结果

  1. <?xml version="1.0" encoding="utf-8" standalone="yes"?> 
  2. <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
  3.   <xs:element name="Table" nillable="true" type="Table" /> 
  4.   <xs:complexType name="Table"> 
  5.     <xs:sequence> 
  6.       <xs:element minOccurs="0" maxOccurs="unbounded" name="Row" type="Order" /> 
  7.     </xs:sequence> 
  8.     <xs:attribute name="CreateTime" type="xs:string" /> 
  9.   </xs:complexType> 
  10.   <xs:complexType name="ArrayOfOrderItems"> 
  11.     <xs:sequence> 
  12.       <xs:element minOccurs="0" maxOccurs="unbounded" name="OrderItem" type="OrderItem" /> 
  13.     </xs:sequence> 
  14.   </xs:complexType> 
  15.   <xs:complexType name="Product"> 
  16.     <xs:attribute name="ProductId" type="xs:int" /> 
  17.     <xs:attribute name="ProductName" type="xs:string" /> 
  18.     <xs:attribute name="TypeName" type="xs:string" /> 
  19.   </xs:complexType> 
  20.   <xs:complexType name="OrderItem"> 
  21.     <xs:sequence> 
  22.       <xs:element minOccurs="0" maxOccurs="1" name="Product" type="Product" /> 
  23.     </xs:sequence> 
  24.     <xs:attribute name="OrderId" type="xs:int" /> 
  25.     <xs:attribute name="UnitPrice" type="xs:decimal" /> 
  26.     <xs:attribute name="Quantity" type="xs:decimal" /> 
  27.     <xs:attribute name="TypeName" type="xs:string" /> 
  28.   </xs:complexType> 
  29.   <xs:complexType name="Order"> 
  30.     <xs:sequence> 
  31.       <xs:element minOccurs="0" maxOccurs="1" name="OrderItems" type="ArrayOfOrderItems" /> 
  32.     </xs:sequence> 
  33.     <xs:attribute name="OrderID" type="xs:int" /> 
  34.     <xs:attribute name="CustomerID" type="xs:string" /> 
  35.     <xs:attribute name="EmployeeID" type="xs:int" /> 
  36.     <xs:attribute name="OrderDate" type="xs:dateTime" /> 
  37.     <xs:attribute name="TypeName" type="xs:string" /> 
  38.   </xs:complexType> 
  39. </xs:schema> 

创建XSD架构文件第六部分:合法的数据文件范例

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <Table Name="Orders" CreateTime="2009/8/9 21:59:04"> 
  3.   <Row TypeName="DataEntities.Order" OrderID="10249" CustomerID="ABCDEF" EmployeeID="1" OrderDate="2009-08-09T21:59:04.125+08:00"> 
  4.     <OrderItems> 
  5.       <OrderItem TypeName="DataEntities.OrderItem" OrderId="10249" UnitPrice="25" Quantity="4"> 
  6.         <Product TypeName="DataEntities.Product" ProductId="1" ProductName="Pen" /> 
  7.       </OrderItem> 
  8.       <OrderItem TypeName="DataEntities.OrderItem" OrderId="10249" UnitPrice="2" Quantity="2000"> 
  9.         <Product TypeName="DataEntities.Product" ProductId="1" ProductName="Car" /> 
  10.       </OrderItem> 
  11.     </OrderItems> 
  12.   </Row> 
  13.   <Row TypeName="DataEntities.Order" OrderID="10249" CustomerID="ABCDEF" EmployeeID="1" OrderDate="2009-08-10T07:29:51.546875+08:00"> 
  14.     <OrderItems> 
  15.       <OrderItem TypeName="DataEntities.OrderItem" OrderId="10249" UnitPrice="25" Quantity="4"> 
  16.         <Product TypeName="DataEntities.Product" ProductId="1" ProductName="Pen" /> 
  17.       </OrderItem> 
  18.       <OrderItem TypeName="DataEntities.OrderItem" OrderId="10249" UnitPrice="2" Quantity="2000"> 
  19.         <Product TypeName="DataEntities.Product" ProductId="1" ProductName="Car" /> 
  20.       </OrderItem> 
  21.     </OrderItems> 
  22.   </Row> 
  23.   <Row TypeName="DataEntities.Order" OrderID="10249" CustomerID="ABCDEF" EmployeeID="1" OrderDate="2009-08-10T07:30:13.375+08:00"> 
  24.     <OrderItems> 
  25.       <OrderItem TypeName="DataEntities.OrderItem" OrderId="10249" UnitPrice="25" Quantity="4"> 
  26.         <Product TypeName="DataEntities.Product" ProductId="1" ProductName="Pen" /> 
  27.       </OrderItem> 
  28.       <OrderItem TypeName="DataEntities.OrderItem" OrderId="10249" UnitPrice="2" Quantity="2000"> 
  29.         <Product TypeName="DataEntities.Product" ProductId="1" ProductName="Car" /> 
  30.       </OrderItem> 
  31.     </OrderItems> 
  32.   </Row> 
  33.   <Row TypeName="DataEntities.Order" OrderID="10249" CustomerID="ABCDEF" EmployeeID="1" OrderDate="2009-08-10T07:30:43.875+08:00"> 
  34.     <OrderItems> 
  35.       <OrderItem TypeName="DataEntities.OrderItem" OrderId="10249" UnitPrice="25" Quantity="4"> 
  36.         <Product TypeName="DataEntities.Product" ProductId="1" ProductName="Pen" /> 
  37.       </OrderItem> 
  38.       <OrderItem TypeName="DataEntities.OrderItem" OrderId="10249" UnitPrice="2" Quantity="2000"> 
  39.         <Product TypeName="DataEntities.Product" ProductId="1" ProductName="Car" /> 
  40.       </OrderItem> 
  41.     </OrderItems> 
  42.   </Row> 
  43. </Table> 

【编辑推荐】

  1. .NET 4.0的ICustomQueryInterface新特性
  2. .NET Lambda表达式的函数式特性:索引示例
  3. .NET Lambda表达式的语义:字符串列表范例
  4. .NET 3.5扩展方法点评:优点与问题
  5. 各版本.NET委托的写法回顾
责任编辑:彭凡 来源: cnblogs
相关推荐

2013-05-02 10:40:24

xcode

2013-06-03 15:38:16

iOS开发iOS SDK动态Action Sh

2022-04-29 08:00:06

Linux目录网络

2020-11-11 09:49:12

计算架构

2023-04-04 09:15:10

NAPI 框架鸿蒙

2010-08-05 15:46:13

Flex行为Flex效果

2016-12-26 17:28:08

构建业务技术架构

2016-11-10 14:34:15

创业业务技术架构

2020-06-02 10:04:58

IT部门首席信息官CIO

2017-02-10 20:00:17

Linux共享目录命令

2009-08-31 13:53:03

C#创建一个文件

2016-12-07 17:45:44

Linux文件

2022-05-16 08:17:36

装饰器模式

2009-09-10 10:09:46

LINQ to SQL

2019-08-12 09:55:10

GitHub项目终端

2010-07-30 14:50:38

Flex项目

2020-09-29 07:24:14

Python字典数据

2023-12-29 18:53:58

微服务Saga模式

2023-03-13 14:02:31

元宇宙

2019-08-12 13:45:26

GithubGit开源
点赞
收藏

51CTO技术栈公众号