C# 中从 XML 架构生成代码有哪些限制?

发布于 2024-10-14 17:16:23 字数 552 浏览 1 评论 0原文

我看到了一些关于使用 xsd.exe 从 XML 模式生成类的问题,以及有关如何预处理模式(通常使用 XSLT)以解决之前的一些棘手问题的建议。到一代。我的问题是是否可以构建一个 100% 符合 XML 架构的 C# 代码生成器。 xsd.exe 的问题仅仅是其实现问题,还是表明 XML 架构和 C# 之间存在根本的不一致?

特别,我对如何将 XML Schema 中的概念映射到 C# 感兴趣 - 可接受的映射是什么,哪些映射是有争议的,是否存在本质上不可映射的 XML Schema 构造以及是否存在未充分利用的 C# 结构?是否有一个合规性规范可以提供映射规则,以便可以实施和测试?

编辑:为了清楚起见,我完全意识到 XML Schema 不会为我提供完全实现的 C# 接口,我感兴趣的是它是否可以完全映射到 C# 类层次结构。

编辑2:我添加了一个小赏金,因为我有兴趣了解更多细节。

编辑 3:赏金仍然开放,但到目前为止正走向 stakx - 一个很好的答案,但主要处理如何在 XML 模式中复制 C# 结构,而不是相反。不过输入很好。

I've seen several questions regarding problems with generating classes from XML Schema using xsd.exe, along with suggestions for how to pre-process the schema (often using XSLT) to resolve some of the trickier aspects prior to generation. My question is whether it's possible to construct a C# code generator that is 100% compliant with XML Schema. Are the problems with xsd.exe merely a question of its implementation, or do they point to a fundamental inconsistency between XML Schema and C#?

In particular, I'm interested in how to map concepts in XML Schema to C# - what are the accepted mappings, which mappings are debatable, are there XML Schema constructs that are inherently un-mappable and are there C# constructs that are underutilised? Is there a compliance specification that would provide rules for mapping, such that it could be implemented and tested?

EDIT: For the sake of clarity I'm fully aware that XML Schema won't provide me with fully implemented C# interfaces, I'm interested in whether it can be fully mapped to a C# class hierarchy.

EDIT 2: I've added a small bounty, as I'm interested in getting a bit more detail.

EDIT 3: Bounty still open, but so far heading toward stakx - a good answer but mainly dealing with how to replicate C# structures in XML Schema, rather than the other way round. Good input though.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

橘香 2024-10-21 17:16:23

有趣的问题。不久前,我也在想同样的事情。

我将展示几个例子来说明我已经走了多远。我的演示并不完整(考虑到 XML 模式规范相当全面),但它应该足以表明...

  • 可以xsd.exe< 做得更好/code>(如果您在编写 XML 架构时愿意遵守某些模式);
  • XML 架构允许无法用 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 模式等效项。

请注意映射的一些问题:

  • C# 访问修饰符(例如 publicinternal 等)无法在 XML 架构中呈现。

  • 您无法表达 C# 字段和 XML 架构中的属性之间的差异。

  • 您无法在 XML 架构中定义方法。

  • 您也无法表达 C# structclass 之间的区别。 (XML 架构中只有简单类型,它们大致对应于 .NET 值类型;但它们在 XML 架构中比复杂类型受到更多限制。)

  • usage="optional" 的用法可用于映射可为空的类型。在 XML 模式中,您可以将字符串属性定义为可选。转换到 C# 时,会发生一些翻译损失:由于 string 是引用类型,因此不能将其声明为可为空(因为默认情况下它已经可为空)。

  • XML 架构还允许 usage="prohibited"。这又是无法用 C# 表达的,或者至少不能以一种很好的方式表达的(AFAIK)。

  • 根据我的实验,xsd.exe 似乎永远不会从抽象复杂类型生成 C# 接口;它将保留在抽象类中。 (我猜这是为了保持翻译逻辑相当简单。)

声明抽象类

抽象类的完成方式与接口非常相似:

<xsd:element name="FooBase" abstract="true">
  <xsd:complexType>
    ...
  </xsd:complexType>
</xsd:element>

在这里,您定义一个元素,并将 abstract 属性设置为 < code>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# 代码片段包含两次 ...,而 XML 架构片段只有一次 ...。怎么会这样?

    因为您无法定义方法(代码),并且也无法指定访问修饰符,所以不需要使用 XML 架构中的元素“实现”复杂类型。复杂类型的“实现”将与原始声明相同。如果复杂类型定义了一些属性,这些属性将简单地映射到 C# 接口实现中的自动属性。

在 XML 模式中表达继承关系

XML 模式中的类和接口继承可以通过类型扩展和元素替换组的组合来定义:

<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 的替换组中;同时,复杂类型衍生是复杂类型base的扩展。 Derived 具有 衍生 类型,Base 具有 base 类型。

  • 非抽象的命名复杂类型在 C# 中没有直接对应的类型。它们不是类,因为它们无法实例化(在 XML 中,元素,而不是类型,与 F# 中的值构造函数或 C# 中的对象实例化具有大致相同的功能) ;它们也不是真正的接口,因为它们没有声明为抽象的。

我的答案中没有涵盖的一些内容

  • 显示如何在 XML 架构中声明实现多个接口的 C# 类类型。

  • 显示 XML 架构中的复杂内容如何映射到 C#(我的第一个猜测是 C# 中根本没有对应关系;至少在一般情况下没有)。

  • 枚举。 (顺便说一句,它们是通过枚举限制简单类型在 XML Schema 中实现的。)

  • 类中的

    const 字段(这些字段可能会映射到带有 <代码>固定值)。

  • 如何将 xsd:choicexsd:sequence 映射到 C#;如何正确映射 IEnumerableICollectionIListIDictionary< /code> 到 XML 模式?


  • XML Schema 简单类型,听起来像是 .NET 值类型的对应概念;但受到更多限制并且有不同的目的。

还有很多很多东西我没有展示,但是现在您可能已经可以看到我的示例背后的基本模式了。

为了正确地完成这一切,人们必须系统地浏览 XML Schema 规范,并了解其中提到的每个概念如何最好映射到 C#。 (也许没有单一的最佳解决方案,而是有几种替代方案。)但我明确表示仅展示几个有趣的示例。我希望这仍然提供了足够的信息!

Interesting question. Not too long ago, I was wondering about exactly the same thing.

I will show a couple examples of how far I got. My demonstration will not be complete (considering that the XML Schema specification is fairly comprehensive), but it should suffice to show...

  • that you can do better than xsd.exe (if you're willing to adhere to certain patterns when you write your XML Schema); and
  • that XML Schema allows type declarations that cannot be expressed in C#. This should not come as a big surprise, considering that XML and C# are very different languages with quite different purposes.

Declaring an interface in XML Schema

C# interfaces can be defined in XML Schema with complex types. For example:

<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>

corresponds fairly well to:

interface IFoo
{
    string Bar { get; set; }
    int?   Baz { get; set; }
}

The pattern here is that abstract and named (non-anonymous) complex types are basically the XML Schema equivalent of interfaces in C#.

Note some problems with the mapping:

  • C# access modifiers such as public, internal etc. cannot be rendered in XML Schema.

  • You have no way of expressing the difference between a C# field and a property in XML Schema.

  • You cannot define methods in XML Schema.

  • You also have no way of expressing the difference between a C# struct and class. (There's simply types in XML Schema, which roughly correspond to .NET value types; but they're much more restricted in XML Schema than complex types.)

  • The usage of usage="optional" can be used to map nullable types. In XML Schema, you could define a string attribute as optional. Crossing over to C#, some loss in translation occurs: Since string is a reference type, it cannot be declared as nullable (since it's already nullable by default).

  • XML Schema also allows usage="prohibited". This is again something that cannot be expressed in C#, or at least in a nice fashion (AFAIK).

  • From my experiments, it appears that xsd.exe will never generate C# interfaces from abstract complex types; it will stay with abstract classes instead. (I'm guessing that this is to keep the translation logic reasonably simple.)

Declaring abstract classes

Abstract classes can be done very similarly to interfaces:

<xsd:element name="FooBase" abstract="true">
  <xsd:complexType>
    ...
  </xsd:complexType>
</xsd:element>

Here, you define an element with the abstract attribute set to true, and embed an anonymous complex type inside it.

This corresponds to the following type declaration in C#:

abstract class FooBase { ... }

Declaring classes

As above, but omit the abstract="true".

Declaring classes that implement an interface

<xsd:complexType name="IFoo" abstract="true">
  ...
</xsd:complexType>

<xsd:element name="Foo" type="IFoo" />

This maps to:

interface IFoo { ... }

class Foo : IFoo { ... }

That is, you define both a named, abstract complex type (the interface), and a named element with that type.

  • Note that the C# code snippet above contains ... twice, while the XML Schema snippet has only one .... How come?

    Because you cannot define methods (code), and because you also cannot specify access modifiers, you don't need to "implement" a complex type with the element in XML Schema. The "implementation" of the complex type would be identical to the original declaration. If the complex type defines some attributes, these simply get mapped to auto-properties in a C# interface implementation.

Expressing inheritance relationships in XML Schema

Class and interface inheritance in XML Schema can be defined through a combination of type extensions and element substitution groups:

<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>

This maps to:

class Base
{
    bool Foo { get; set; }
}

class Derived : Base
{
    string Bar { get; set; }
}

Note:

  • We're again using named complex types. But this time, they're not defined abstract="true", since we're not defining any C# interface type.

  • Note the references: Element Derived is in Base's substitution group; at the same time, complex type derived is an extension of complex type base. Derived has type derived, Base has type base.

  • Named complex types that are not abstract have no direct counterpart in C#. They're not classes, since they cannot be instantiated (in XML, elements, not types, have roughly the same function as value constructors in F# or object instantiation in C#); neither are they truly interfaces, since they are not declared abstract.

Some things that I haven't covered in my answer

  • Showing how one would declare, in XML Schema, a C# class type that implements several interfaces.

  • Showing how complex content in XML Schema maps to C# (my first guess it that there's no correspondence in C# at all; at least not in the general case).

  • enums. (They are realised in XML Schema by restricting a simple type via enumeration, btw.)

  • const fields in a class (these would possibly map to attributes with a fixed value).

  • How to map xsd:choice, xsd:sequence to C#; How to correctly map IEnumerable<T>, ICollection<T>, IList<T>, IDictionary<TKey, TValue> to XML Schema?

  • XML Schema simple types, which sound like they're the corresponding concept of .NET value types; but are far more restricted and have a different purpose.

There's many many more things that I haven't shown, but by now you can probably see the basic patterns behind my examples.

To do all this correctly, one would have to systematically go through the XML Schema specification and see how each concept mentioned there maps best to C#. (There's perhaps no single best solution, but several alternatives.) But I explicitly meant to show only a couple of interesting examples. I hope that was still informative enough!

浅忆流年 2024-10-21 17:16:23

这不是代码生成的限制。 XML 模式不描述类。它描述的是 XML,这是另一回事。

结果是 XML 模式和 C# 类、Java 类或任何其他类型的类之间存在“阻抗不匹配”。两者并不等同,也不应该等同。

It's not a limit to code generation. It's that XML schema does not describe classes. It describes XML, which is a different thing.

The result is that there is an "impedance mismatch" between XML Schema and C# classes, or Java classes, or any other kind of classes. The two are not equivalent, and are not meant to be.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文