2008-12-02 22 views
20

este código C# probablemente no sea el más eficiente, pero obtiene lo que quiero hacer.F # análisis XML

¿Cómo logro lo mismo en el código F #?

string xml = " <EmailList> " + 
       "  <Email>[email protected]</Email> " + 
       "  <Email>[email protected]</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 ; 
     }    
    } 

Respuesta

47
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 

Si realmente se desea que el salto de línea final de arrastre se puede añadir en el mapa y String.concat con la cadena vacía.

1

Si mira su código, tiene un par de cosas en marcha. El primero es cargar la colección para los nodos de correo electrónico, y el segundo es realmente hacer algo significativo con ellos.

En primer lugar, querría que su función devuelva una colección. Algo así como (y estoy en mi Mac, por lo que este podría no funcionar):


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(); 
     }    
    } 
} 

Ahora surge la pregunta en torno a lo que quiere hacer con esa colección. En tu ejemplo anterior, lo estabas concatenando, o básicamente almacenando el estado.

Desde una perspectiva de C#, puede comenzar a usar cosas como las respuestas de this question (usando LINQ) y this one.

Desde una perspectiva F #, ahora tiene una lista y puede simplemente usar los procedimientos normales para una lista como this one o here.

También puede consultar LINQ to XML (o al 5 minute overview) para obtener más ideas.

1

¿Qué tal algo a lo largo de las líneas de:

#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 
+0

? No puedo compilar las líneas IEnumerable. ¿De dónde sacas este tipo? – JaredPar

+0

¿Hay alguna razón en particular para usar IEnumerable.iter en lugar de Seq.iter? No hay diferencia entre los dos, Seq es más idiomático F #. – Juliet

+0

No, aparte de que no he programado F # en un par de años. :-) –

6

Aquí es un código similar a hacer esto en C#. Estoy seguro de que uno de los ninjas F # pondrá una mejor versión aquí en un minuto.

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() 
5

Lo mismo con el F# Data XML Type Provider:

type EmailList = XmlProvider<"""<EmailList><Email>email</Email><Email>email</Email></EmailList>"""> 
let data = EmailList.Parse(""" 
    <EmailList> 
     <Email>[email protected]</Email> 
     <Email>[email protected]</Email> 
    </EmailList> 
    """) 

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