如何递归获取 XmlProvider 的所有 XElement 子项
How can I recursively get all XElement children for an XmlProvider
我正在尝试使用 F# 为 C# 构建动态 type/class 构建器,来自以下 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
值收集到 sequence/List 作为递归结果的提示。我也可以忍受最后有一个 XElement
的列表。
函数flatten
需要return一个序列,而不是一个单一的东西。
对于具有子元素的元素,您需要为每个元素调用 flatten
,然后连接所有结果:
e.Elements() |> Seq.map flatten |> Seq.concat
(注意XElement.Elements
是方法,不是属性,所以调用时需要加上()
)
对于单个元素,只需 return 它的名称包裹在单个元素序列中:
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
参数,我认为这不是参数,而是试图声明函数的 return类型;可以省略;作为参考,F# 中的函数 return 类型在函数签名后用冒号声明,例如 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
}
我正在尝试使用 F# 为 C# 构建动态 type/class 构建器,来自以下 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
值收集到 sequence/List 作为递归结果的提示。我也可以忍受最后有一个 XElement
的列表。
函数flatten
需要return一个序列,而不是一个单一的东西。
对于具有子元素的元素,您需要为每个元素调用 flatten
,然后连接所有结果:
e.Elements() |> Seq.map flatten |> Seq.concat
(注意XElement.Elements
是方法,不是属性,所以调用时需要加上()
)
对于单个元素,只需 return 它的名称包裹在单个元素序列中:
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
参数,我认为这不是参数,而是试图声明函数的 return类型;可以省略;作为参考,F# 中的函数 return 类型在函数签名后用冒号声明,例如 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
}