Jam*_*ord 18 c# xml xsd code-generation
我已经看到了几个关于使用XML Schema生成类的问题的问题xsd.exe,以及如何预先处理模式(通常使用XSLT)来解决生成之前的一些棘手方面的建议.我的问题是,是否可以构建一个100%符合XML Schema的C#代码生成器.问题xsd.exe仅仅是它的实现问题,还是它们指向XML Schema和C#之间的根本不一致?
特别是,我对如何将XML Schema中的概念映射到C#感兴趣 - 什么是可接受的映射,哪些映射是有争议的,是否存在本质上不可映射的XML Schema构造,是否存在未充分利用的C#构造?是否存在可提供映射规则的合规性规范,以便可以实施和测试?
编辑:为了清楚起见,我完全清楚XML Schema不会为我提供完全实现的C#接口,我对它是否可以完全映射到C#类层次结构感兴趣.
编辑2:我添加了一笔小额奖金,因为我有兴趣获得更多细节.
编辑3:赏金仍然开放,但到目前为止走向stakx - 一个很好的答案,但主要是处理如何在XML Schema中复制C#结构,而不是相反.虽然输入很好.
sta*_*ica 26
有趣的问题.不久前,我想知道完全相同的事情.
我将展示一些我有多远的例子.我的演示将不完整(考虑到XML Schema规范相当全面),但它应该足以显示......
xsd.exe(如果你愿意,当你写你的XML Schema来遵守一定的模式); 和可以使用复杂类型在XML Schema中定义C#接口.例如:
<xsd:complexType name="IFoo" abstract="true">
<xsd:attribute name="Bar" type="xsd:string" use="required" />
<xsd:attribute name="Baz" type="xsd:int" use="optional" />
</xsd:complexType>
Run Code Online (Sandbox Code Playgroud)
对应得很好:
interface IFoo
{
string Bar { get; set; }
int? Baz { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
这里的模式是抽象和命名(非匿名)复杂类型基本上是C#中接口的XML Schema等价物.
请注意映射的一些问题:
C#访问修饰符如public,internal等无法在XML架构来呈现.
您无法在XML Schema中表达C#字段和属性之间的区别.
您无法在XML Schema中定义方法.
你也无法表达C#struct和C#之间的区别class.(XML Schema中有简单的类型,它大致对应于.NET值类型;但它们在XML Schema中比复杂类型更受限制.)
用法usage="optional"可用于映射可空类型.在XML Schema中,您可以将字符串属性定义为可选.转换到C#时,会发生一些转换损失:由于string是引用类型,因此不能将其声明为可为空(因为默认情况下它已经可以为空).
XML Schema也允许usage="prohibited".这又是一个无法用C#表达的东西,或者至少是一种不错的方式(AFAIK).
从我的实验,似乎xsd.exe将永远不会产生从抽象复杂类型C#接口; 它将与abstract classes 保持一致.(我猜这是为了使翻译逻辑保持相当简单.)
抽象类可以与接口非常相似地完成:
<xsd:element name="FooBase" abstract="true">
<xsd:complexType>
...
</xsd:complexType>
</xsd:element>
Run Code Online (Sandbox Code Playgroud)
在这里,您定义一个abstract属性设置为的元素true,并在其中嵌入一个匿名复杂类型.
这对应于C#中的以下类型声明:
abstract class FooBase { ... }
Run Code Online (Sandbox Code Playgroud)
如上所述,但省略了abstract="true".
<xsd:complexType name="IFoo" abstract="true">
...
</xsd:complexType>
<xsd:element name="Foo" type="IFoo" />
Run Code Online (Sandbox Code Playgroud)
这映射到:
interface IFoo { ... }
class Foo : IFoo { ... }
Run Code Online (Sandbox Code Playgroud)
也就是说,您既定义了命名的抽象复杂类型(接口),又定义了具有该类型的命名元素.
请注意,上面的C#代码段包含...两次,而XML Schema代码段只有一个....怎么会?
因为您无法定义方法(代码),并且因为您也无法指定访问修饰符,所以您不需要使用XML Schema中的元素"实现"复杂类型.复杂类型的"实现"与原始声明相同.如果复杂类型定义了一些属性,则这些属性只会映射到C#接口实现中的自动属性.
XML Schema中的类和接口继承可以通过类型扩展和元素替换组的组合来定义:
<xsd:element name="Base" type="base" />
<xsd:element name="Derived" substitutionGroup="Base" type="derived" />
<!-- ^^^^^^^^^^^^^^^^^^^^^^^^ -->
<xsd:complexType name="base">
<xsd:attribute name="Foo" type="xsd:boolean" use="required" />
</xsd:complexType>
<xsd:complexType name="derived">
<xsd:complexContent>
<xsd:extension base="base"> <!-- !!! -->
<xsd:attribute name="Bar" type="xsd:string" use="required" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
Run Code Online (Sandbox Code Playgroud)
这映射到:
class Base
{
bool Foo { get; set; }
}
class Derived : Base
{
string Bar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
注意:
我们再次使用命名复杂类型.但是这一次,它们没有被定义abstract="true",因为我们没有定义任何C#接口类型.
注意引用:元素Derived在Base替换组中; 同时,复杂类型derived是复杂类型的扩展base.Derived有类型derived,Base有类型base.
非抽象的命名复杂类型在C#中没有直接对应的.它们不是类,因为它们不能被实例化(在XML中,元素,而不是类型,与F#中的值构造函数或C#中的对象实例化具有大致相同的功能); 它们都不是真正的接口,因为它们不是抽象的.
展示如何在XML Schema中声明实现多个接口的C#类类型.
显示XML Schema中的复杂内容如何映射到C#(我首先猜测C#中没有对应关系;至少在一般情况下不是这样).
enum秒.(通过限制简单类型来实现它们在XML Schema中enumeration,顺便说一下.)
const类中的字段(这些字段可能映射到具有fixed值的属性).
如何映射xsd:choice,xsd:sequence到C#; 如何正确地映射IEnumerable<T>,ICollection<T>,IList<T>,IDictionary<TKey, TValue>XML模式?
XML Schema简单类型,听起来像是.NET值类型的相应概念; 但是受到更多限制并且有不同的目的.
还有很多我没有展示过的东西,但到现在为止你可能会看到我的例子背后的基本模式.
要正确地完成所有这些操作,必须系统地完成XML Schema规范并查看其中提到的每个概念如何最好地映射到C#.(可能没有单一的最佳解决方案,但有几种选择.)但我明确表示只展示几个有趣的例子.我希望这仍然足够丰富!