使用F#数据按顺序循环遍历多个/不同的xml元素

时间:2015-01-14 15:05:31

标签: f# f#-data


是否可以使用F#循环遍历以下文档,伪代码实际上是伪的:)

<root>
   <element_a>1</element_a>
   <element_b>2</element_b>
   <element_c>3</element_c>
   <element_a>4</element_a>
</root>

伪代码:

root.? |> Array.iter ( fun e ->
   printfn "%s:%s" e.DisplayName e.Value
)

结果:

element_a:1
element_b:2
element_c:3
element_a:4

所以,

  1. 我可以按原始顺序循环浏览不同的元素吗?
  2. 如果是,我怎么知道它是哪个元素?

2 个答案:

答案 0 :(得分:1)

XML类型提供程序不会为您提供任何类型化的方法。也就是说,可以按顺序访问所有孩子,作为一些提供类型的集合,这将是一个有用的扩展!

但是,您可以使用基础XElement表示来迭代所有子项,然后将它们转回由XML类型提供程序生成的静态类型表示。

使用你的基本例子,所有元素的类型都被推断为int,所以这并不是那么有趣(没有孩子......),但是你说你有这样的东西,其中不同的元素全部具有属性a的相同子元素n

type Demo = XmlProvider<"""<root>
   <element_a><a n="foo" /></element_a>
   <element_b><a n="bar" /></element_b>
   <element_c><a n="zoo" /></element_c>
   <element_a><a n="goo" /></element_a>
</root>""">

现在,您可以使用root.XElement.Descendants()

以无类型方式获取元素
let root = Demo.GetSample()
for child in root.XElement.Descendants() do
  let asA = new Demo.ElementA(child)
  printfn "%A" asA.A.N

一旦我们有了子元素,我们就会将它重新包装成一个静态类型的表示。在这里,我们总是使用为<element_a>生成的类型(这可能是错误的 - 如果其他元素具有不同的结构,但它在这里工作得很好。)

答案 1 :(得分:0)

你可以生成一个XDocument并遍历根的孩子:

#r "System.XML.Linq"
open System.IO;
open System.Xml.Linq;

let xml = @"
            <root>
               <element_a>1</element_a>
               <element_b>2</element_b>
               <element_c>3</element_c>
               <element_a>4</element_a>
            </root>"
let xdoc = XDocument.Load(new StringReader(xml))
let rootEl = xdoc.Elements() |> Seq.head
rootEl.Elements() |> Seq.iter (fun el -> printfn "%s: %s" el.Name.LocalName el.Value)

应该产生所需的输出。

如果要区分同名的元素,可以将Seq.iterSeq.iteri交换,将序号索引传递给提供的函数:

rootEl.Elements() |> Seq.iteri (fun idx el -> printfn "Idx %d: %s: %s" idx el.Name.LocalName el.Value)

产生

Idx 0: element_a: 1
Idx 1: element_b: 2
Idx 2: element_c: 3
Idx 3: element_a: 4