XML 从 C# 扫描到 F#
XML scan from C# to F#
尝试学习 F#,并尝试在 F# 中重新实现以下函数
private string[] GetSynonyms(string synonyms)
{
var items = Enumerable.Repeat(synonyms, 1)
.Where(s => s != null)
.Select(XDocument.Parse)
.Select(doc => doc.Root)
.Where(root => root != null)
.SelectMany(e => e.Elements(SynonymsNamespace + "synonym"))
.Select(e => e.Value)
.ToArray();
return items;
}
我一个人走到这一步
let xname = XNamespace.Get "http://localuri"
let syn = "<synonyms xmlns=\"http://localuri\"><synonym>a word</synonym><synonym>another word</synonym></synonyms>"
let synonyms str =
let items = [str]
items
|> List.map System.Xml.Linq.XDocument.Parse
|> List.map (fun x -> x.Root)
|> List.map (fun x -> x.Elements(xname + "synonym") |> Seq.cast<System.Xml.Linq.XElement>)
|> Seq.collect (fun x -> x)
|> Seq.map (fun x -> x.Value)
let a = synonyms syn
Dump a
现在我想知道是否有更实用的方法来编写相同的代码。
通过提取对独立函数的属性的访问,我得到了这个版本
let xname = XNamespace.Get "http://localuri"
let syn = "<synonyms xmlns=\"http://localuri\"><synonym>a word</synonym><synonym>another word</synonym></synonyms>"
let getRoot (doc:System.Xml.Linq.XDocument) = doc.Root
let getValue (element:System.Xml.Linq.XElement) = element.Value
let getElements (element:System.Xml.Linq.XElement) =
element.Elements(xname + "synonym")
|> Seq.cast<System.Xml.Linq.XElement>
let synonyms str =
let items = [str]
items
|> List.map System.Xml.Linq.XDocument.Parse
|> List.map getRoot
|> List.map getElements
|> Seq.collect (fun x -> x)
|> Seq.map getValue
let a = synonyms syn
Dump a
但我还有一些顾虑
- 我可以用另一种方式重写 Seq.collect (fun x -> x) 吗?听起来多余
- 我可以在不创建新函数的情况下删除所有这些 (fun x -> x.Property) 吗?
- 如何实际 return 一个数组而不是一个 Seq<'a>(我理解是一个 IEnumerable<'a>)
谢谢
Seq.collect (fun x -> x) 可以用预定义的id函数重写为 Seq.collect id
在 F# 4.0 中,只能为构造函数删除它。
使用Seq.toArray或Seq.toList
放弃 C# 代码并完全使用 F# 中的 XML-provider 会不会非常错误?在我的世界里,当存在其他解决方案时,总是 解析 XML 是错误的(除非我试图制造八角轮或其他在我之前做得更好的湿火药)。
在这方面,我什至会使用一些转换 (XSLT) 或选择 (XPATH/XQUERY),除非我可以使用 XML-provider 或一些 XSD (c#)生成代码。
如果由于某种原因 XML 如此非结构化以至于您实际上需要解析,那么 XML 可以说是错误的...
如果使用 XmlProvider,您可以免费获得命名空间、类型等...
#r @"..\correct\this\path\to\packages\FSharp.Data.2.2.5\lib\net40\FSharp.Data.dll"
#r "System.Xml.Linq"
open FSharp.Data
[<Literal>]
let syn = "<synonyms xmlns=\"http://localuri\"><synonym>a word</synonym><synonym>another word</synonym></synonyms>"
type Synonyms = XmlProvider<syn>
let a = Synonyms.GetSample()
a.Synonyms |> Seq.iter (printfn "%A")
请注意,XmlProvider 也可以将文件或 url 作为推断类型等的示例,您也可以将此代码作为示例,然后使用
let a = Synonyms.Load(stuff)
其中 stuff 是从流、文本阅读器或 URI 中读取并根据您的示例推断的。如果这是一些标准的数据放置,样本和内容甚至可能指向相同的 file/Uri。
另请参阅:http://fsharp.github.io/FSharp.Data/library/XmlProvider.html
尝试学习 F#,并尝试在 F# 中重新实现以下函数
private string[] GetSynonyms(string synonyms)
{
var items = Enumerable.Repeat(synonyms, 1)
.Where(s => s != null)
.Select(XDocument.Parse)
.Select(doc => doc.Root)
.Where(root => root != null)
.SelectMany(e => e.Elements(SynonymsNamespace + "synonym"))
.Select(e => e.Value)
.ToArray();
return items;
}
我一个人走到这一步
let xname = XNamespace.Get "http://localuri"
let syn = "<synonyms xmlns=\"http://localuri\"><synonym>a word</synonym><synonym>another word</synonym></synonyms>"
let synonyms str =
let items = [str]
items
|> List.map System.Xml.Linq.XDocument.Parse
|> List.map (fun x -> x.Root)
|> List.map (fun x -> x.Elements(xname + "synonym") |> Seq.cast<System.Xml.Linq.XElement>)
|> Seq.collect (fun x -> x)
|> Seq.map (fun x -> x.Value)
let a = synonyms syn
Dump a
现在我想知道是否有更实用的方法来编写相同的代码。
通过提取对独立函数的属性的访问,我得到了这个版本
let xname = XNamespace.Get "http://localuri"
let syn = "<synonyms xmlns=\"http://localuri\"><synonym>a word</synonym><synonym>another word</synonym></synonyms>"
let getRoot (doc:System.Xml.Linq.XDocument) = doc.Root
let getValue (element:System.Xml.Linq.XElement) = element.Value
let getElements (element:System.Xml.Linq.XElement) =
element.Elements(xname + "synonym")
|> Seq.cast<System.Xml.Linq.XElement>
let synonyms str =
let items = [str]
items
|> List.map System.Xml.Linq.XDocument.Parse
|> List.map getRoot
|> List.map getElements
|> Seq.collect (fun x -> x)
|> Seq.map getValue
let a = synonyms syn
Dump a
但我还有一些顾虑
- 我可以用另一种方式重写 Seq.collect (fun x -> x) 吗?听起来多余
- 我可以在不创建新函数的情况下删除所有这些 (fun x -> x.Property) 吗?
- 如何实际 return 一个数组而不是一个 Seq<'a>(我理解是一个 IEnumerable<'a>)
谢谢
Seq.collect (fun x -> x) 可以用预定义的id函数重写为 Seq.collect id
在 F# 4.0 中,只能为构造函数删除它。
使用Seq.toArray或Seq.toList
放弃 C# 代码并完全使用 F# 中的 XML-provider 会不会非常错误?在我的世界里,当存在其他解决方案时,总是 解析 XML 是错误的(除非我试图制造八角轮或其他在我之前做得更好的湿火药)。
在这方面,我什至会使用一些转换 (XSLT) 或选择 (XPATH/XQUERY),除非我可以使用 XML-provider 或一些 XSD (c#)生成代码。
如果由于某种原因 XML 如此非结构化以至于您实际上需要解析,那么 XML 可以说是错误的...
如果使用 XmlProvider,您可以免费获得命名空间、类型等...
#r @"..\correct\this\path\to\packages\FSharp.Data.2.2.5\lib\net40\FSharp.Data.dll"
#r "System.Xml.Linq"
open FSharp.Data
[<Literal>]
let syn = "<synonyms xmlns=\"http://localuri\"><synonym>a word</synonym><synonym>another word</synonym></synonyms>"
type Synonyms = XmlProvider<syn>
let a = Synonyms.GetSample()
a.Synonyms |> Seq.iter (printfn "%A")
请注意,XmlProvider 也可以将文件或 url 作为推断类型等的示例,您也可以将此代码作为示例,然后使用
let a = Synonyms.Load(stuff)
其中 stuff 是从流、文本阅读器或 URI 中读取并根据您的示例推断的。如果这是一些标准的数据放置,样本和内容甚至可能指向相同的 file/Uri。
另请参阅:http://fsharp.github.io/FSharp.Data/library/XmlProvider.html