.NET : 如何动态根据一个业务实体类型创建XSD架构文件
2009-08-10 11:55
976 查看
这是正在开发的XML数据库的一个功能,我需要动态根据一个业务实体类型创建一个XSD架构文件,并使用其对最后的XML数据文件进行约束。
目前该功能仅仅是一个原型,还有待细化改进。例如在实体的成员上用一些特定的Attribute标明该成员要被保存的形态。
此处特别注意的是,Order这个类是很复杂的,它包含了一系列的OrderItem,而OrderItem又包含了Product对象。
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
本文由作者:陈希章于2009/8/1011:55:00
发布在:博客园,转载请注明出处
目前该功能仅仅是一个原型,还有待细化改进。例如在实体的成员上用一些特定的Attribute标明该成员要被保存的形态。
第一部分:业务实体类
(作为演示目的,我将所有的类型定义在一个文件里,同时每个类都只有少量简单的属性成员)此处特别注意的是,Order这个类是很复杂的,它包含了一系列的OrderItem,而OrderItem又包含了Product对象。
usingSystem; usingSystem.Collections.Generic; usingSystem.Text; namespaceDataEntities { publicclassOrder { publicintOrderID{get;set;} publicstringCustomerID{get;set;} publicintEmployeeID{get;set;} publicDateTimeOrderDate{get;set;} publicList<OrderItem>OrderItems{get;set;} publicoverridestringToString() { StringBuildersb=newStringBuilder(); sb.AppendFormat("\t{0}\t{1}\t{2}\t{3}",OrderID,CustomerID,EmployeeID,OrderDate); sb.AppendLine(); foreach(variteminOrderItems) { sb.AppendFormat("\t\t{0}\t{1}\t{2}\n",item.Product.ProductName,item.UnitPrice,item.Quantity); } returnsb.ToString(); } } publicclassOrderItem { publicintOrderId{get;set;} publicProductProduct{get;set;} publicdecimalUnitPrice{get;set;} publicdecimalQuantity{get;set;} } publicclassProduct { publicintProductId{get;set;} publicstringProductName{get;set;} } }
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
第二部分:生成XSD的工具类(Utility.cs)
usingSystem; usingSystem.Xml.Linq; usingSystem.Collections; usingSystem.Xml; namespaceXMLDatabase { publicclassUtility { ///<summary> ///使用指定类型生成一个架构文件 ///</summary> ///<typeparamname="T"></typeparam> publicstaticvoidXsdGenerate<T>(XmlWriterxw){ Typet=typeof(T); XNamespacexn="http://www.w3.org/2001/XMLSchema"; XDocumentdoc=newXDocument( newXDeclaration("1.0","utf-8","yes"), newXElement(xn+"schema", newXAttribute("elementFormDefault","qualified"), newXAttribute(XNamespace.Xmlns+"xs","http://www.w3.org/2001/XMLSchema"), newXElement(xn+"element", newXAttribute("name","Table"), newXAttribute("nillable","true"), newXAttribute("type","Table")) )); XElementtableElement=newXElement(xn+"complexType", newXAttribute("name","Table")); tableElement.Add( newXElement(xn+"sequence", newXElement(xn+"element", newXAttribute("minOccurs","0"), newXAttribute("maxOccurs","unbounded"), newXAttribute("name","Row"), newXAttribute("type",t.Name) )), newXElement(xn+"attribute", newXAttribute("name","CreateTime"), newXAttribute("type","xs:string")) ); doc.Root.Add(tableElement); CreateComplexType(t,doc.Root); doc.Save(xw); } privatestaticvoidCreateComplexType(Typet,XElementroot){ XNamespacexn=root.GetNamespaceOfPrefix("xs"); XElementtemp=newXElement( xn+"complexType", newXAttribute("name",t.Name)); #region循环所有属性 foreach(varpint.GetProperties())//循环所有属性 { TypepType=p.PropertyType; stringfullType=pType.FullName; //这里仍然是分几种情况 if(!GeneralType.Contains(fullType)) { varseqelement=temp.Element(xn+"sequence"); if(seqelement==null) { seqelement=newXElement(xn+"sequence"); temp.AddFirst(seqelement); } if(pType.IsEnum)//如果是枚举 { seqelement.Add( newXElement( xn+"element", newXAttribute("minOccurs","0"), newXAttribute("maxOccurs","1"), newXAttribute("name",p.Name), newXAttribute("type",pType.Name))); XElementenumElement=newXElement( xn+"complexType", newXAttribute("name",pType.Name), newXElement(xn+"attribute", newXAttribute("name","Enum"), newXAttribute("type","xs:string"))); root.Add(enumElement); } elseif(pType.GetInterface(typeof(IList).FullName)!=null&&pType.IsGenericType) //如果是集合,并且是泛型集合 { TypeitemType=pType.GetGenericArguments()[0]; seqelement.Add( newXElement( xn+"element", newXAttribute("minOccurs","0"), newXAttribute("maxOccurs","1"), newXAttribute("name",p.Name), newXAttribute("type","ArrayOf"+p.Name))); XElementarrayElement=newXElement( xn+"complexType", newXAttribute("name","ArrayOf"+p.Name), newXElement(xn+"sequence", newXElement(xn+"element", newXAttribute("minOccurs","0"), newXAttribute("maxOccurs","unbounded"), newXAttribute("name",itemType.Name), newXAttribute("type",itemType.Name)))); root.Add(arrayElement); CreateComplexType(itemType,root); } elseif(pType.IsClass||pType.IsValueType) { seqelement.Add( newXElement( xn+"element", newXAttribute("minOccurs","0"), newXAttribute("maxOccurs","1"), newXAttribute("name",p.Name), newXAttribute("type",pType.Name))); CreateComplexType(pType,root); } } else { //这种情况最简单,属性为标准内置类型,直接作为元素的Attribute即可 temp.Add( newXElement(xn+"attribute", newXAttribute("name",p.Name), newXAttribute("type",GeneralType.ConvertXSDType(pType.FullName)))); } } #endregion temp.Add(newXElement(xn+"attribute", newXAttribute("name","TypeName"), newXAttribute("type","xs:string"))); root.Add(temp); } } }
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
第三部分:辅助类型(GeneralType.cs).
这个类型中有一个方法可以将业务实体类型成员属性的类型转换为XSD中的类型。usingSystem; usingSystem.Collections.Generic; usingSystem.Text; namespaceXMLDatabase { publicclassGeneralType { privatestaticreadonlyList<string>generalTypes=newList<string>() { "System.Byte",//typeof(byte).FullName, "System.SByte",//typeof(sbyte).FullName, "System.Int16",//typeof(short).FullName, "System.UInt16",//typeof(ushort).FullName, "System.Int32",//typeof(int).FullName, "System.UInt32",//typeof(uint).FullName, "System.Int64",//typeof(long).FullName, "System.UInt64",//typeof(ulong).FullName, "System.Double",//typeof(double).FullName, "System.Decimal",//typeof(decimal).FullName, "System.Single",//typeof(float).FullName, "System.Char",//typeof(char).FullName, "System.Boolean",//typeof(bool).FullName, "System.String",//typeof(string).FullName, "System.DateTime"//typeof(DateTime).FullName }; ///<summary> ///判断当前给定类型是否为默认的数据类型 ///</summary> ///<paramname="fullType"></param> ///<returns></returns> publicstaticboolContains(stringfullType) { returngeneralTypes.Contains(fullType); } publicstaticstringConvertXSDType(stringfullType) { switch(fullType) { case"System.String": return"xs:string"; case"System.Int32": return"xs:int"; case"System.DateTime": return"xs:dateTime"; case"System.Boolean": return"xs:boolean"; case"System.Single": return"xs:float"; case"System.Byte": return"xs:byte"; case"System.SByte": return"xs:unsignedByte"; case"System.Int16": return"xs:short"; case"System.UInt16": return"xs:unsignedShort"; case"System.UInt32": return"xs:unsignedInt"; case"System.Int64": return"xs:long"; case"System.UInt64": return"xs:unsignedLong"; case"System.Double": return"xs:double"; case"System.Decimal": return"xs:decimal"; default: break; } returnstring.Empty; } } }
第四部分:单元测试
///<summary>
///XsdGenerate的测试
///</summary>
publicvoidXsdGenerateTestHelper<T>()
{
XmlWriterxw=XmlWriter.Create("Order.xsd");//TODO:初始化为适当的值
Utility.XsdGenerate<Order>(xw);
xw.Close();
}
第五部分:生成的结果
<?xmlversion="1.0"encoding="utf-8"standalone="yes"?>
<xs:schemaelementFormDefault="qualified"xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:elementname="Table"nillable="true"type="Table"/>
<xs:complexTypename="Table">
<xs:sequence>
<xs:elementminOccurs="0"maxOccurs="unbounded"name="Row"type="Order"/>
</xs:sequence>
<xs:attributename="CreateTime"type="xs:string"/>
</xs:complexType>
<xs:complexTypename="ArrayOfOrderItems">
<xs:sequence>
<xs:elementminOccurs="0"maxOccurs="unbounded"name="OrderItem"type="OrderItem"/>
</xs:sequence>
</xs:complexType>
<xs:complexTypename="Product">
<xs:attributename="ProductId"type="xs:int"/>
<xs:attributename="ProductName"type="xs:string"/>
<xs:attributename="TypeName"type="xs:string"/>
</xs:complexType>
<xs:complexTypename="OrderItem">
<xs:sequence>
<xs:elementminOccurs="0"maxOccurs="1"name="Product"type="Product"/>
</xs:sequence>
<xs:attributename="OrderId"type="xs:int"/>
<xs:attributename="UnitPrice"type="xs:decimal"/>
<xs:attributename="Quantity"type="xs:decimal"/>
<xs:attributename="TypeName"type="xs:string"/>
</xs:complexType>
<xs:complexTypename="Order">
<xs:sequence>
<xs:elementminOccurs="0"maxOccurs="1"name="OrderItems"type="ArrayOfOrderItems"/>
</xs:sequence>
<xs:attributename="OrderID"type="xs:int"/>
<xs:attributename="CustomerID"type="xs:string"/>
<xs:attributename="EmployeeID"type="xs:int"/>
<xs:attributename="OrderDate"type="xs:dateTime"/>
<xs:attributename="TypeName"type="xs:string"/>
</xs:complexType>
</xs:schema>
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
第六部分:合法的数据文件范例
<?xmlversion="1.0"encoding="utf-8"?>
<TableName="Orders"CreateTime="2009/8/921:59:04">
<RowTypeName="DataEntities.Order"OrderID="10249"CustomerID="ABCDEF"EmployeeID="1"OrderDate="2009-08-09T21:59:04.125+08:00">
<OrderItems>
<OrderItemTypeName="DataEntities.OrderItem"OrderId="10249"UnitPrice="25"Quantity="4">
<ProductTypeName="DataEntities.Product"ProductId="1"ProductName="Pen"/>
</OrderItem>
<OrderItemTypeName="DataEntities.OrderItem"OrderId="10249"UnitPrice="2"Quantity="2000">
<ProductTypeName="DataEntities.Product"ProductId="1"ProductName="Car"/>
</OrderItem>
</OrderItems>
</Row>
<RowTypeName="DataEntities.Order"OrderID="10249"CustomerID="ABCDEF"EmployeeID="1"OrderDate="2009-08-10T07:29:51.546875+08:00">
<OrderItems>
<OrderItemTypeName="DataEntities.OrderItem"OrderId="10249"UnitPrice="25"Quantity="4">
<ProductTypeName="DataEntities.Product"ProductId="1"ProductName="Pen"/>
</OrderItem>
<OrderItemTypeName="DataEntities.OrderItem"OrderId="10249"UnitPrice="2"Quantity="2000">
<ProductTypeName="DataEntities.Product"ProductId="1"ProductName="Car"/>
</OrderItem>
</OrderItems>
</Row>
<RowTypeName="DataEntities.Order"OrderID="10249"CustomerID="ABCDEF"EmployeeID="1"OrderDate="2009-08-10T07:30:13.375+08:00">
<OrderItems>
<OrderItemTypeName="DataEntities.OrderItem"OrderId="10249"UnitPrice="25"Quantity="4">
<ProductTypeName="DataEntities.Product"ProductId="1"ProductName="Pen"/>
</OrderItem>
<OrderItemTypeName="DataEntities.OrderItem"OrderId="10249"UnitPrice="2"Quantity="2000">
<ProductTypeName="DataEntities.Product"ProductId="1"ProductName="Car"/>
</OrderItem>
</OrderItems>
</Row>
<RowTypeName="DataEntities.Order"OrderID="10249"CustomerID="ABCDEF"EmployeeID="1"OrderDate="2009-08-10T07:30:43.875+08:00">
<OrderItems>
<OrderItemTypeName="DataEntities.OrderItem"OrderId="10249"UnitPrice="25"Quantity="4">
<ProductTypeName="DataEntities.Product"ProductId="1"ProductName="Pen"/>
</OrderItem>
<OrderItemTypeName="DataEntities.OrderItem"OrderId="10249"UnitPrice="2"Quantity="2000">
<ProductTypeName="DataEntities.Product"ProductId="1"ProductName="Car"/>
</OrderItem>
</OrderItems>
</Row>
</Table>
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
本文由作者:
发布在:
相关文章推荐
- .NET : 如何动态根据一个业务实体类型创建XSD架构文件
- java中如何使用asm动态的生成或修改一个class文件以及asm的架构思想
- 在.NET上如何根据字符串动态创建控件【转载】
- 在.NET上如何根据字符串动态创建控件
- 在.NET上如何根据字符串动态创建控件
- 在.NET上如何根据字符串动态创建控件
- 在.NET上如何根据字符串动态创建控件
- 练习 2017-08-22 通过控制台,获取类名,字段名称,字段类型,根据一个模板文件,自动创建这个类文件,并且为字段提供setter和getter方法
- 在.NET上如何根据字符串动态创建控件
- 在.NET上如何根据字符串动态创建控件
- 在.NET上如何根据字符串动态创建控件
- 如何构建一个ERP系统(需求分析、系统架构、系统设计、系统编码、测试、交付程序及文文件)。
- Lipo - 如何为ARMv7/ARMv7s/ARM64架构 创建通用文件(Universal Files)
- 如何创建一个动态的数据窗口对象
- Android Studio 中如何创建一个新的工程以及库文件的创建以及引用
- .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)
- 如何创建一个XML文件,然后创建一个与之关联的样式表文件?
- 如何通过配置文件动态创建对象
- 如何修改一个视频文件的创建时间
- 让函数根据一个以上的对象类型来决定如何虚化