2017-02-21 92 views
7

我们正在考虑将来为我们的项目充分利用F#,并希望能够自动从F#类型生成.xsd模式。有没有办法为F#类型生成.xsd?

在Web上搜索会返回很多从.xsd生成类型的答案,但不是相反。

有没有人知道如何做到这一点?

回答

4

这种依赖于你实际上的含义。

如果您的意思是:“我如何从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文件”,然后你那种倒霉的(据我所知)。

+0

谢谢你的回答,Helge。为了充分利用F#的简洁性,我们确实希望自己为F#类型生成.xsd,而不是为底层的CLI类型生成.xsd。我们将通过.dll尝试这种方法,以了解它的外观,但仍然希望有更直接的映射可用。 –

0

我可能是错的,但我没有看到如何以某种方式实现这一点,比使用基于XSD的F#类型提供程序更实用,如果有足够好的工作。但是,我不确定是否有一个。

尝试使用FSharp.Data.Xsd类型提供程序。您可以在源中将XSD指定为字符串,或者通过引用源外部的XSD文件。它可能无法创建任何您想要的XSD。

我认为问题在于F#类型本身并不是一种实际的方式来指定XSD应该是什么样子,除非您做出一些妥协,可能您没有做好准备。

  • 你会在F#中创建一些特定的类型来控制映射吗?我不认为使用这种类型将是“利用F#”。

  • 你会使用代码属性或其他元数据吗?在这种情况下,是不是更好地编辑XSD而不是F#类型?

  • 你会简单地创建一些暗示一对一映射的规则吗?它可以工作,但可能不会产生你想要的XSD和XML。它可能变得太冗长。

您将不得不生成XSD。另一方面,如果您使用类型提供程序从XSD生成F#类型,则生成的类型将立即可用。这不是更实际和令人愉快吗?

0

我会用'typeclasses'来解决这个问题。快速示例(在REPL中)。 假设您有Person类型,如 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的 全部 - 你只需要你的类型实际使用的部分。

0

如果您想从您的代码中直接生成任何类型的XSD,请查看此F#脚本。它生成一个F#记录类型的XSD。脚本使用三个.NET程序集:System.Runtime.Serialization.dll,System.Runtime.Serialization.Xml,System.Xml

#r "System.Runtime.Serialization.dll" 
#r "System.Runtime.Serialization.Xml.dll" 
#r "System.Xml.dll" 

open System 
open System.IO 
open System.Linq 
open System.Text 
open System.Text.RegularExpressions 
open System.Xml 
open System.Runtime.Serialization 

type [<DataContract>] CommitInfo = { 
    [<field: DataMember(Name="id") >] 
    id: string 
    [<field: DataMember(Name="date") >] 
    date: DateTime 
    [<field: DataMember(Name="issueUrl") >] 
    issueUrl: string 
    [<field: DataMember(Name="issueId") >] 
    issueId: int 
    [<field: DataMember(Name="message") >] 
    message: string 
    [<field: DataMember(Name="url") >] 
    url: string 
} 

let getXmlWriter (stream: Stream) = 
    //let utf8noBOM = new UTF8Encoding(false) 
    let settings = new XmlWriterSettings() 
    settings.Indent <- true 
    settings.Encoding <- Encoding.UTF8 
    //settings.OmitXmlDeclaration <- true 
    XmlWriter.Create(stream, settings) 

let streamToString (stream: Stream) = 
    stream.Position <- int64 0 
    use sr = new StreamReader(stream) 
    sr.ReadToEnd() 

let getResultFromStream (streamWriter: Stream -> unit) = 
    use stream = new MemoryStream() 
    streamWriter stream 
    streamToString stream 

let exporter = XsdDataContractExporter() 
exporter.Export(typeof<CommitInfo array>) 
let schemas = exporter.Schemas.Schemas().Cast<Schema.XmlSchema>() |> Array.ofSeq 
let schema = schemas.[1] 

fun s -> s |> getXmlWriter |> schema.Write 
|> getResultFromStream 
|> printfn "%s" 
相关问题