在 C# 中从 XML Schema 生成代码的限制是啥?
Posted
技术标签:
【中文标题】在 C# 中从 XML Schema 生成代码的限制是啥?【英文标题】:What are the limits to code generation from XML Schema in C#?在 C# 中从 XML Schema 生成代码的限制是什么? 【发布时间】:2011-06-18 02:06:20 【问题描述】:我已经看到了几个关于使用xsd.exe
从 XML Schema 生成类的问题的问题,以及关于如何预处理模式(通常使用 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# 结构,而不是相反。不过很好的输入。
【问题讨论】:
@marc_s - 我对相反的方向更感兴趣,XML Schema -> C#,我没想到能够将 XML Schema 用作编程语言! xsd.exe 未完全映射所有 xml 架构约定。此外,某些映射并不完美 - 例如有趣的问题。不久前,我想知道完全相同的事情。
我将展示几个例子来说明我已经走了多远。我的演示将不完整(考虑到 XML Schema 规范相当全面),但应该足以展示......
您可以比xsd.exe
做得更好(如果您在编写 XML Schema 时愿意遵守某些模式);和
XML Schema 允许不能用 C# 表达的类型声明。考虑到 XML 和 C# 是非常不同的语言,用途也大不相同,这不应该让人感到意外。
在 XML Schema 中声明接口
C# 接口可以在具有复杂类型的 XML Schema 中定义。例如:
<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>
相当好地对应于:
interface IFoo
string Bar get; set;
int? Baz get; set;
这里的模式是抽象和命名(非匿名)复杂类型基本上是 C# 中接口的 XML Schema 等价物。
注意映射的一些问题:
public
、internal
等 C# 访问修饰符无法在 XML Schema 中呈现。
您无法表达 C# 字段和 XML Schema 中的属性之间的区别。
您不能在 XML Schema 中定义方法。
您也无法表达 C# struct
和 class
之间的区别。 (XML Schema 中有简单的类型,大致对应于 .NET 值类型;但它们在 XML Schema 中的限制比复杂类型要大得多。)
usage="optional"
的用法可用于映射可空类型。在 XML Schema 中,您可以将字符串属性定义为可选。跨到 C# 时,会出现一些翻译损失:由于 string
是引用类型,因此不能将其声明为可为空(因为默认情况下它已经可为空)。
XML Schema 也允许usage="prohibited"
。这又是不能用 C# 表达的东西,或者至少不能用一种很好的方式表达 (AFAIK)。
从我的实验来看,xsd.exe
似乎永远不会从抽象复杂类型生成 C# 接口;它将与abstract class
es 保持一致。 (我猜这是为了保持翻译逻辑相当简单。)
声明抽象类
抽象类可以与接口非常相似:
<xsd:element name="FooBase" abstract="true">
<xsd:complexType>
...
</xsd:complexType>
</xsd:element>
在这里,您定义了一个将abstract
属性设置为true
的元素,并在其中嵌入了一个匿名复杂类型。
这对应于 C# 中的以下类型声明:
abstract class FooBase ...
声明类
同上,但省略abstract="true"
。
声明实现接口的类
<xsd:complexType name="IFoo" abstract="true">
...
</xsd:complexType>
<xsd:element name="Foo" type="IFoo" />
这映射到:
interface IFoo ...
class Foo : IFoo ...
也就是说,您既定义了一个命名的抽象复杂类型(接口),又定义了一个具有该类型的命名元素。
请注意,上面的 C# 代码 sn-p 包含两次...
,而 XML Schema sn-p 只有一个...
。怎么会?
因为你不能定义方法(代码),并且因为你也不能指定访问修饰符,所以你不需要用 XML Schema 中的元素“实现”一个复杂的类型。复杂类型的“实现”将与原始声明相同。如果复杂类型定义了一些属性,这些属性会简单地映射到 C# 接口实现中的自动属性。
在 XML Schema 中表达继承关系
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>
这映射到:
class Base
bool Foo get; set;
class Derived : Base
string Bar get; set;
注意:
我们再次使用命名复杂类型。但是这一次,它们没有定义abstract="true"
,因为我们没有定义任何 C# 接口类型。
注意引用:元素Derived
在Base
的替换组中;同时,复杂类型derived
是复杂类型base
的扩展。 Derived
的类型为 derived
,Base
的类型为 base
。
非抽象的命名复杂类型在 C# 中没有直接对应物。它们不是类,因为它们不能被实例化(在 XML 中,elements,而不是 types,与 F# 中的值构造函数或 C# 中的对象实例化具有大致相同的功能) ;它们也不是真正的接口,因为它们没有被声明为抽象的。
我的回答中没有涉及到的一些事情
展示如何在 XML Schema 中声明实现几个接口的 C# 类类型。
显示 XML Schema 中的复杂内容如何映射到 C#(我首先猜测 C# 中根本没有对应关系;至少在一般情况下没有)。
enum
s。 (它们在 XML Schema 中通过 enumeration
限制简单类型来实现,顺便说一句。)
const
类中的字段(这些可能会映射到具有fixed
值的属性)。
如何将xsd:choice
、xsd:sequence
映射到C#;如何正确映射IEnumerable<T>
、ICollection<T>
、IList<T>
、IDictionary<TKey, TValue>
到 XML Schema?
XML Schema 简单类型,听起来像是 .NET 值类型的对应概念;但受到更多限制并且有不同的目的。
还有很多我没有展示的东西,但现在您可能已经看到了我的示例背后的基本模式。
要正确完成这一切,必须系统地阅读 XML Schema 规范,并了解其中提到的每个概念如何将 最佳 映射到 C#。 (也许没有单一的最佳解决方案,但有几个替代方案。)但我明确表示只展示几个有趣的例子。我希望这仍然提供足够的信息!
【讨论】:
一个有趣的答案,它处理了我的很多想法,尽管从相反的角度来看(C# => XML Schema 而不是 XML Schema => C#)。谢谢。【参考方案2】:这不是代码生成的限制。就是 XML 模式不描述类。它描述了 XML,这是另一回事。
结果是 XML Schema 与 C# 类、Java 类或任何其他类型的类之间存在“阻抗不匹配”。两者不等价,也不应该是等价的。
【讨论】:
然而,使用 XML Schema 来提供代码大纲是很常见的。显然我们不能使用 XML Schema 来提供这样的接口,我对尝试在 XML Schema 中复制 C# 不感兴趣。我对从 XML Schema 到 C# 的可能概念映射可能在哪里分崩离析感兴趣。换句话说,阻抗失配只是一种方式吗? @James:你将如何映射xs:choice
或混合内容?
@John Saunders - 这几乎是我一开始的问题!混合内容只是“轻微”的特殊情况,因为它是一系列文本节点和子元素。
@James:您如何将其映射到 OO?您将不得不使用IEnumerable<XNode>
或同样无用的东西。没有有用的映射。
@John Saunders:我感谢您在该领域的专业知识,并且忘记它的建议并不难遵循,因为我一开始就没有尝试过 :-) 我不过,我仍然对这篇长论文感兴趣!以上是关于在 C# 中从 XML Schema 生成代码的限制是啥?的主要内容,如果未能解决你的问题,请参考以下文章