有没有办法为F#类型生成.xsd?
我们正在考虑在未来将F#用于我们的项目,并希望能够自动从F#类型生成.xsd模式。
在Web上搜索会返回很多从.xsd生成类型的答案,但不是相反。
有没有人知道一种方法来做到这一点?
这种依赖于你实际上的意思。
如果您的意思是:“我如何从dll生成XSD?” 那么它可以很简单地完成与svcutil ...好吧,考虑到其他一些条件得到满足,但有点可行:
以下命令为装配中的服务合同和关联类型生成元数据文档。
svcutil myAssembly.dll
https://msdn.microsoft.com/en-us/library/aa347733(v=vs.110).aspx
xsd.exe也应该能够做同样的事情。 我不知道这里的条件是什么,但是文档并不像svcutil那么“严格”。
以下命令为程序集myAssembly.dll中的所有类型生成XML模式,并将它们作为schema0.xsd保存在当前目录中。
xsd myAssembly.dll
https://msdn.microsoft.com/en-us/library/x6c1kb0s(v=vs.110).aspx
如果你的意思是“从给定的* .fs文件生成XSD”,那么你有点不幸(据我所知)。
我可能是错的,但我不明白如何才能以比使用基于XSD的F#类型提供者更实用的方式来实现,如果有足够好的工作。 但是,我不确定是否有一个。
尝试使用FSharp.Data.Xsd类型提供程序。 您可以在源中将XSD指定为字符串,或者通过引用源外部的XSD文件。 它可能无法创建任何您想要的XSD。
我认为,问题在于F#类型本身并不是一种指定XSD应该是什么样子的实用方法,除非您做出一些妥协,或许您不打算做出。
你会在F#中创建一些特定类型来控制映射吗? 我不认为使用这种类型将是“利用F#”。
你会使用代码属性或其他元数据? 在这种情况下,是不是更好地编辑XSD而不是F#类型?
你会简单地创建一些暗示一对一映射的规则吗? 它可以工作,但可能不会产生你想要的XSD和XML。 它可能变得太冗长。
你将不得不生成XSD。 另一方面,如果您使用类型提供程序从XSD生成F#类型,则生成的类型将立即可用。 这不是更实际和令人愉快吗?
我会用'typeclasses'来解决这个问题。 快速示例(在REPL中)。 假设你有一个Person
类型,比如type Person = { id : int64; name : string}
type Person = { id : int64; name : string}
。 然后:
> ("id", Xsd.int64, "name", Xsd.string)
|> Xsd.record2 "Person"
|> Xsd.root
|> Xsd.to_string;;
val it : string =
"<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="Person">
<xsd:sequence>
<xsd:element name="id" type="long"/>
<xsd:element name="name" type="string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>"
这是通过在Xsd
模块中为每种类型放置很少的转换器函数以及类型的组合(即总和和产品类型)来实现的。 这应该涵盖大多数需求。 Xsd
模块的外观可能如下所示:
(* xsd.fsi *)
/// Just a string marked by the type of data whose XSD it holds.
/// Implementation is private so that callers can't create any XSD
/// they like.
type 'a t
/// Gives us the string representation of the XSD.
val to_string : 'a t -> string
/// Wraps an XSD encoding inside the <xsd:schema> tag pair.
val root : 'a t -> 'a t
// Primitive types.
val int : int t
val int64 : int64 t
val string : string t
/// Encode a two-field record's type (name and fields along with their
/// types) as XSD.
val record2 : string -> string * 'a1 t * string * 'a2 t -> 'a t
(* xsd.fs *)
type 'a t = { to_string : string }
let to_string xsd = xsd.to_string
let root xsd =
{ to_string =
sprintf "<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
%s
</xsd:schema>" xsd.to_string }
let int = { to_string = "integer" }
let int64 = { to_string = "long" }
let string = { to_string = "string" }
/// Helper for record fields.
let element name typ =
sprintf "<xsd:element name="%s" type="%s"/>" name typ
let record2 name (field1, xsd1, field2, xsd2) =
{ to_string =
sprintf
"<xsd:complexType name="%s">
<xsd:sequence>
%s
%s
</xsd:sequence>
</xsd:complexType>"
name
(element field1 xsd1.to_string)
(element field2 xsd2.to_string) }
无可否认,与使用运行时反射相比,这是一种不熟悉的技术。 但它也更加类型安全,并且可以更好地控制编码。 你也可能不需要实现所有的XSD - 你只需要你的类型实际使用的部分。
链接地址: http://www.djcxy.com/p/95265.html