Xml在不同scheme的不同文件中的公共部分的类型?
The type of the common piece of Xml in different files with different scheme?
我有以下代码来处理几个不同的 xml 文件(不同的方案),它们都有 <parameters>
的节点。现在我发现 match
部分将在很多地方使用,所以我想为它创建一个函数。
let xml1 = XmlProvider<"./file1.xml">.Parse(resp)
match xml1.Parameters |> Seq.tryFind (fun x -> x.Name = "token") with
| Some value -> value.Value |> Some
| None -> None
let xml2 = XmlProvider<"./file2.xml">.Parse(resp) // different scheme but has <parameters>
match xml2.Parameters |> Seq.tryFind (fun x -> x.Name = "token") with
| Some value -> value.Value |> Some
| None -> None
// more very different files but has <parameters> ......
在上面的示例中,您可以看到重复了 match
部分。如何定义函数?
let getToken (parameters : <what the type?>) =
match parameters |> Seq.tryFind (fun x -> x.Name = "token") with
| Some value -> value.Value |> Some
| None -> None
parameters
的类型应该是什么?
更新:
我已经更新了问题。顺便说一句,这是一个显示结构类型有用性的案例吗?
这是用于测试的代码(尚无法运行)。 xml1
和 xml2
有完全不同的 xml 方案,除了它们都有 <parameters>
部分。
let input1 = """<r1><parameters><parameter name="token">1</parameter><parameter name="other">xxx</parameter></parameters><othersOf1>..sample....</othersOf1></r1>"""
let xml1 = XmlProvider<"""<r1><parameters><parameter name="token">1</parameter><parameter name="other">xxx</parameter></parameters><othersOf1>...</othersOf1></r1>""">.Parse(input1)
let input2 = """<r2><parameters><parameter name="token">1</parameter><parameter name="other">xxx</parameter></parameters><othersOf2>...sample...</othersOf2></r2>"""
let xml2 = XmlProvider<"""<r2><parameters><parameter name="token">1</parameter><parameter name="other">xxx</parameter></parameters><othersOf2>...</othersOf2></r2>""">.Parse(input2)
let getToken (parameters: ????) =
match parameters |> Seq.tryFind (fun x -> x.Name = "token") with
| Some value -> value.Value |> Some
| None -> None
let token1 = getToken xml1.Parameters
let token2 = getToken xml2.Parameters
一般来说,嵌套节点的类型成为XML类型提供者提供的类型的嵌套类型。
要访问类型,您首先需要使用类型别名并命名您提供的类型:
type DbToken = XmlProvider<"""<parameters>
<parameter name="token" value="123" />
<parameter name="token" value="123" />
</parameters>""">
我正在使用内联 XML 示例,以便我可以对其进行测试,但它应该与文件相同。
文件中单个 <parameter />
节点的类型现在是 DbToken.Parameter
(名称是自动生成的唯一且可能会有所不同),因此我们现在可以编写一个函数:
let getToken (parameters:DbToken.Parameter[]) =
match parameters |> Seq.tryFind (fun x -> x.Name = "token") with
| Some value -> value.Value |> Some
| None -> None
下面的调用有效:
let xml = DbToken.GetSample()
getToken xml.Parameters
我们的想法是拥有一个函数,该函数接受某种类型 ^P
的 seq
,该类型具有 Name
和 Value
。出于教育目的,Name
可以是任何类型 'a
(支持相等)并且 Value
是通用类型 'b
:
let inline get name parameters =
parameters |> Seq.tryFind (fun x -> (^P : (member Name : 'a) x) = name)
|> Option.map (fun v -> (^P : (member Value : 'b) v))
将一些值 <parameter name="token" value="123">
添加到 XML1 并将名称更改为 int
以及在 XML2 <parameter name="12" value="2016-12-31">
中具有 DateTime
值允许获得:
let token1 = get "token" xml1.Parameters // : int option
let token2 = get 12 xml2.Parameters // : DateTime option
所以,是的,你是对的,这可以利用结构类型来完成。
parameters
的实际类型也取决于 name
。 get
的完整类型是:
name:'a -> parameters:seq< ^P> -> 'b option
when 'a : equality and ^P : (member get_Name : ^P -> 'a) and
^P : (member get_Value : ^P -> 'b)
我有以下代码来处理几个不同的 xml 文件(不同的方案),它们都有 <parameters>
的节点。现在我发现 match
部分将在很多地方使用,所以我想为它创建一个函数。
let xml1 = XmlProvider<"./file1.xml">.Parse(resp)
match xml1.Parameters |> Seq.tryFind (fun x -> x.Name = "token") with
| Some value -> value.Value |> Some
| None -> None
let xml2 = XmlProvider<"./file2.xml">.Parse(resp) // different scheme but has <parameters>
match xml2.Parameters |> Seq.tryFind (fun x -> x.Name = "token") with
| Some value -> value.Value |> Some
| None -> None
// more very different files but has <parameters> ......
在上面的示例中,您可以看到重复了 match
部分。如何定义函数?
let getToken (parameters : <what the type?>) =
match parameters |> Seq.tryFind (fun x -> x.Name = "token") with
| Some value -> value.Value |> Some
| None -> None
parameters
的类型应该是什么?
更新: 我已经更新了问题。顺便说一句,这是一个显示结构类型有用性的案例吗?
这是用于测试的代码(尚无法运行)。 xml1
和 xml2
有完全不同的 xml 方案,除了它们都有 <parameters>
部分。
let input1 = """<r1><parameters><parameter name="token">1</parameter><parameter name="other">xxx</parameter></parameters><othersOf1>..sample....</othersOf1></r1>"""
let xml1 = XmlProvider<"""<r1><parameters><parameter name="token">1</parameter><parameter name="other">xxx</parameter></parameters><othersOf1>...</othersOf1></r1>""">.Parse(input1)
let input2 = """<r2><parameters><parameter name="token">1</parameter><parameter name="other">xxx</parameter></parameters><othersOf2>...sample...</othersOf2></r2>"""
let xml2 = XmlProvider<"""<r2><parameters><parameter name="token">1</parameter><parameter name="other">xxx</parameter></parameters><othersOf2>...</othersOf2></r2>""">.Parse(input2)
let getToken (parameters: ????) =
match parameters |> Seq.tryFind (fun x -> x.Name = "token") with
| Some value -> value.Value |> Some
| None -> None
let token1 = getToken xml1.Parameters
let token2 = getToken xml2.Parameters
一般来说,嵌套节点的类型成为XML类型提供者提供的类型的嵌套类型。
要访问类型,您首先需要使用类型别名并命名您提供的类型:
type DbToken = XmlProvider<"""<parameters>
<parameter name="token" value="123" />
<parameter name="token" value="123" />
</parameters>""">
我正在使用内联 XML 示例,以便我可以对其进行测试,但它应该与文件相同。
文件中单个 <parameter />
节点的类型现在是 DbToken.Parameter
(名称是自动生成的唯一且可能会有所不同),因此我们现在可以编写一个函数:
let getToken (parameters:DbToken.Parameter[]) =
match parameters |> Seq.tryFind (fun x -> x.Name = "token") with
| Some value -> value.Value |> Some
| None -> None
下面的调用有效:
let xml = DbToken.GetSample()
getToken xml.Parameters
我们的想法是拥有一个函数,该函数接受某种类型 ^P
的 seq
,该类型具有 Name
和 Value
。出于教育目的,Name
可以是任何类型 'a
(支持相等)并且 Value
是通用类型 'b
:
let inline get name parameters =
parameters |> Seq.tryFind (fun x -> (^P : (member Name : 'a) x) = name)
|> Option.map (fun v -> (^P : (member Value : 'b) v))
将一些值 <parameter name="token" value="123">
添加到 XML1 并将名称更改为 int
以及在 XML2 <parameter name="12" value="2016-12-31">
中具有 DateTime
值允许获得:
let token1 = get "token" xml1.Parameters // : int option
let token2 = get 12 xml2.Parameters // : DateTime option
所以,是的,你是对的,这可以利用结构类型来完成。
parameters
的实际类型也取决于 name
。 get
的完整类型是:
name:'a -> parameters:seq< ^P> -> 'b option
when 'a : equality and ^P : (member get_Name : ^P -> 'a) and
^P : (member get_Value : ^P -> 'b)