有没有办法为F#类型生成.xsd?

时间:2017-02-21 16:42:24

标签: xsd f#

我们希望将来能够将F#用于我们的项目,并且希望能够自动从F#类型生成.xsd架构。

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

有人知道这样做的方法吗?

4 个答案:

答案 0 :(得分: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"那么你有点不走运(据我所知)。

答案 1 :(得分:0)

我可能是错的,但我不知道如何以比使用基于XSD的F#类型提供程序更实用的方式实现这一点,如果有一个工作得很好的话。但是,我不确定是否有一个。

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

我认为,问题在于单独使用F#类型并不是指定XSD应该是什么样子的实用方法,除非你做出一些可能你不准备做出的妥协。

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

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

  • 您是否只是创建一些暗示一对一映射的规则?它可以工作,但可能无法生成您想要的XSD和XML。它可能变得过于冗长。

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

答案 2 :(得分: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 - 您只需要您的类型实际使用的部分。

答案 3 :(得分:0)

如果要直接从代码生成任何类型的XSD,请查看此F#脚本。它生成一个F#记录类型的XSD。脚本使用三个.NET程序集:System.Runtime.Serialization.XmlSystem.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"

skill.sendKeys(Keys.ENTER);