使用F#中的Sequences从对象中选择属性

时间:2017-01-12 12:58:22

标签: xml linq xpath f#

我正在学习F#并且遇到了一个问题,谷歌搜索对我没什么帮助。

我有一个带有XmlNodes的Xml文档,它是使用Xpath选择的。我已经过滤了属性,属性集合可以从Seq返回。但是,当我返回属性值而不是属性时,编译期间会显示以下错误

This expression was expected to have type 'a option
but here has type string

下面给出了代码段

let doc = new System.Xml.XmlDocument() in
                    doc.LoadXml xml;
                    doc.SelectNodes "//*[local-name()='SingleSignOnService']"
                        |> Seq.cast<System.Xml.XmlNode>
                        |> Seq.collect (fun node -> node.Attributes |> Seq.cast<System.Xml.XmlAttribute>)
                        |> Seq.filter (fun attr -> attr.Name.Equals("Binding",StringComparison.OrdinalIgnoreCase))
                        |> Seq.choose(fun attr -> attr.Value)

请建议我正确的方法。

修改

这是我在Mr.Marklam的帮助下形成的解决方案。希望这会有助于其他任何人

let doc = new System.Xml.XmlDocument() in
                    doc.LoadXml xml;
                    doc.SelectNodes "//*[local-name()='SingleSignOnService']"
                        |> Seq.cast<System.Xml.XmlNode>
                        |> Seq.collect (fun node -> node.Attributes |> Seq.cast<System.Xml.XmlAttribute> |> Seq.filter (fun attr -> attr.Name.Equals("Binding",StringComparison.OrdinalIgnoreCase)))
                        |> Seq.choose (fun attr -> if (attr.Name.Equals("Binding",StringComparison.OrdinalIgnoreCase)) then Some attr.Value else None)

2 个答案:

答案 0 :(得分:4)

如果您想使用Seq.choose删除任何null属性值,则应将attr.Value转换为string option

最简单的方法是通过Option.ofObj,即

|> Seq.filter (fun attr -> attr.Name.Equals("Binding",StringComparison.OrdinalIgnoreCase)
|> Seq.choose(fun attr -> attr.Value |> Option.ofObj)

但是如果您知道该值永远不为null,则可以使用

|> Seq.choose (fun attr -> if attr.Name.Equals("Binding",StringComparison.OrdinalIgnoreCase)) then Some attr.Value else None)

答案 1 :(得分:3)

我认为Linq扩展方法存在一些混淆。

map(fun attr -> attr.Value)Select(attr => attr.Value)

choose只是Where(option => option.HasValue).Select(option => option.Value)

以下是C#/ Linq中的更多内容

collectSelectMany

findFirst

foldAggregate

singletonEnumerable.Return