我正在尝试使用F#为C#构建动态类型/类构建器,来自以下XML
<config target="string">
<protocol>string</protocol>
<about_path>string</about_path>
<about_content>
<name_path>string</name_path>
<id_path>string</id_path>
<version_path>string</version_path>
</about_content>
</config>
使用下面的代码我可以很好地解析样本
module XmlParser =
open FSharp.Data
open System.Globalization
open FSharp.Data.Runtime.BaseTypes
open System.Xml.Linq
[<Literal>]
let targetSchema = "<config target=\"string\">
<protocol>string</protocol>
<about_path>string</about_path>
<about_content>
<name_path>string</name_path>
<id_path>string</id_path>
<version_path>string</version_path>
</about_content>
</config>"
type Configuration = XmlProvider<targetSchema>
现在的问题是我无法理解检索about_content
标签的内部部分。
解析实际的xml后使用
let parsedValue = Configuration.Parse(xmlIn)
我试图了解F#中的递归处理,但我仍然坚持看起来像这样的非工作代码(e
将是parsedValue.XElement
)
let rec flatten ( e : System.Xml.Linq.XElement) (out:List<string>) =
if e.HasElements
then for inner in e.Elements -> flatten(inner)
else e.Name.LocalName
我需要的是提示如何将e.Name.LocalName
值作为递归的结果收集到序列/ List中。我也可以忍受在最后有一个XElement
s列表。
函数flatten
需要返回序列,而不是单个事物。
对于具有子元素的元素,您需要为每个元素调用flatten
,然后将所有结果连接起来:
e.Elements() |> Seq.map flatten |> Seq.concat
(请注意,XElement.Elements
是一种方法,而不是属性;因此,您需要添加()
来调用它)
对于单个元素,只需返回包含在单个元素序列中的名称:
Seq.singleton e.Name.LocalName
把它们放在一起:
let rec flatten (e : System.Xml.Linq.XElement) =
if e.HasElements
then e.Elements() |> Seq.map flatten |> Seq.concat
else Seq.singleton e.Name.LocalName
(还要注意我已经删除了你的out
参数,我认为这个参数不是参数,而是试图声明函数的返回类型;它可以省略;作为参考,F#中的函数返回类型是在带冒号的函数签名,例如let f (x:int) : int = x + 5
)
如果您更喜欢更具势在线的风格,可以使用seq
计算表达式。 yield
将产生单个元素,而yield!
将产生另一个序列的每个元素的效果:
let rec flatten (e : System.Xml.Linq.XElement) =
seq {
if e.HasElements then
for i in e.Elements() do
yield! flatten i
else
yield e.Name.LocalName
}