F# XML解析

26

这段C#代码可能不是最高效的,但能够实现我想要的功能。

我该如何在F#代码中完成同样的事情?

    string xml = " <EmailList> " +
               "      <Email>test@email.com</Email> " +
               "      <Email>test2@email.com</Email> " +
               " </EmailList> ";

    XmlDocument xdoc = new XmlDocument();
    XmlNodeList nodeList;
    String emailList = string.Empty;
    xdoc.LoadXml(xml);
    nodeList = xdoc.SelectNodes("//EmailList");
    foreach (XmlNode item in nodeList)
    {
        foreach (XmlNode email in item)
        {
             emailList +=  email.InnerText.ToString() +  Environment.NewLine ;
        }               
    }
5个回答

52
let doc = new XmlDocument() in
    doc.LoadXml xml;
    doc.SelectNodes "/EmailList/Email/text()"
        |> Seq.cast<XmlNode>
        |> Seq.map (fun node -> node.Value)
        |> String.concat Environment.NewLine

如果你确实想要最后一个换行符,你可以在 map 中添加它,并使用空字符串与 String.concat 连接。


10

F#数据XML类型提供程序相同:

type EmailList = XmlProvider<"""<EmailList><Email>email</Email><Email>email</Email></EmailList>""">
let data = EmailList.Parse("""
    <EmailList>
        <Email>test@email.com</Email>
        <Email>test2@email.com</Email>
    </EmailList>
    """)

let emailList = data.Emails |> String.concat Environment.NewLine

6

这里是类似的F#代码,用于完成此操作。我相信F#忍者们很快就会在这里发布更好的版本。

open System.Xml

let getList x = 
    let getDoc =
        let doc = new XmlDocument()
        doc.LoadXml(x) |> ignore
        doc
    let getEmail (n:XmlNode) = n.InnerText.ToString() 
    let doc = getDoc
    let build = new System.Text.StringBuilder()
    doc.SelectNodes("//EmailList") 
        |> Seq.cast<XmlNode>
        |> Seq.map (fun n -> n.ChildNodes )
        |> Seq.map_concat (Seq.cast<XmlNode>)
        |> Seq.map(fun (n:XmlNode) -> getEmail n) 
        |> Seq.iter (fun e -> build.AppendLine(e) |> ignore )
    build.ToString()

1

如果你看一下你的代码,会发现有几个事情需要处理。第一个是加载电子邮件节点的集合,第二个是实际上对它们进行有意义的操作。

首先,你需要让你的函数返回一个集合。类似这样(我在我的 Mac 上,所以可能不适用):


List<string> EmailAddresses(string xml)
{
    XmlDocument xdoc = new XmlDocument();
    XmlNodeList nodeList;
    String emailList = string.Empty;
    xdoc.LoadXml(xml);
    nodeList = xdoc.SelectNodes("//EmailList");
    foreach (XmlNode item in nodeList)
    {
        foreach (XmlNode email in item)
        {
             yield email.InnerText.ToString();
        }               
    }
}

现在问题来了,你想用那个集合做什么。在你上面的例子中,你正在连接它,或者基本上是存储状态。

从 C# 的角度来看,你可以开始使用像 this question(使用 LINQ)和 this one 中的答案。

从 F# 的角度来看,你现在有一个列表,可以简单地使用列表的常规程序,如 this onehere

你还可以查看 LINQ to XML(或 5 minute overview)以获取更多想法。


1

类似以下的内容怎样?

#light
open System.Xml

let xml = "..."

let emailList = 
    let xdoc = new XmlDocument()
    xdoc.LoadXml(xml)

    let mutable list = []
    let addEmail e = list <- e :: emailList

    xdoc.SelectNodes("//EmailList")
    |> IEnumerable.iter(fun(item:XmlNode) ->
        item
        |> IEnumerable.iter(fun(e:XmlNode) ->
            addEmail e.InnerText; ()))

    list

我无法将IEnumerable行编译。你从哪里获取这种类型的? - JaredPar
2
使用IEnumerable.iter而不是Seq.iter有什么特别的原因吗?两者之间没有区别,Seq更符合F#的惯用法。 - Juliet
1
不,除了我已经好几年没有编写 F# 了。 :-) - Frank Krueger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接