2010-06-18 35 views
8

Necesito convertir un CSV en un documento XML. Los ejemplos que he visto hasta ahora muestran cómo hacer esto con un número fijo de columnas en el archivo CSV.Convertir archivo CSV a XML

tengo esto hasta ahora, el uso de LINQ:

String[] File = File.ReadAllLines(@"C:\text.csv"); 

     String xml = ""; 

     XElement top = new XElement("TopElement", 

     from items in File 

     let fields = items.Split(';') 

     select new XElement("Item", 

     new XElement("Column1", fields[0]), 

     new XElement("Column2", fields[1]), 

     new XElement("Column3", fields[2]), 

     new XElement("Column4", fields[3]), 

     new XElement("Column5", fields[4]) 

     ) 

     ); 

     File.WriteAllText(@"C:\xmlout.xml", xml + top.ToString()); 

Esto es por una cantidad fija de columnas, pero mi CSV tiene un número diferente de columnas en cada línea.

¿Cómo encajaría algún tipo de bucle en esto, dependiendo de cuántas palabras (columnas) hay en cada línea del .CSV?

Thnx

Respuesta

23
var lines = File.ReadAllLines(@"C:\text.csv"); 

var xml = new XElement("TopElement", 
    lines.Select(line => new XElement("Item", 
     line.Split(';') 
      .Select((column, index) => new XElement("Column" + index, column))))); 

xml.Save(@"C:\xmlout.xml"); 

de entrada:

A;B;C 
D;E;F 
G;H 

Salida:

<TopElement> 
    <Item> 
    <Column0>A</Column0> 
    <Column1>B</Column1> 
    <Column2>C</Column2> 
    </Item> 
    <Item> 
    <Column0>D</Column0> 
    <Column1>E</Column1> 
    <Column2>F</Column2> 
    </Item> 
    <Item> 
    <Column0>G</Column0> 
    <Column1>H</Column1> 
    </Item> 
</TopElement> 
+0

Bastante cerca. Pero necesito dividir cada palabra en cada línea separada por a; Por lo tanto, la salida XML sería algo como esto: palabra palabra palabra palabra palabra palabra palabra casi lo tenía con el código que he publicado, pero sólo me dieron la primera palabra de cada línea.Entonces, necesito agregar algún tipo de bucle, que agregue un elemento Columna para cada palabra en cada línea separada por a; – Soeren

+0

@Soeren: ¿No es eso lo que hace mi solución? He agregado un ejemplo para aclarar. – dtb

+0

Esto funciona genial. La parte line.Split (';') no estaba en el primer ejemplo, e intenté agregarla yo mismo. Simplemente no sabía cómo agregarlo. Necesito estudiar esto de LINQ un poco más. Gracias por tu ayuda. – Soeren

9

En caso de que quiera utilizar los encabezados como los nombres de elementos:

var lines = File.ReadAllLines(@"C:\text.csv"); 
string[] headers = lines[0].Split(',').Select(x => x.Trim('\"')).ToArray(); 

var xml = new XElement("TopElement", 
    lines.Where((line, index) => index > 0).Select(line => new XElement("Item", 
     line.Split(',').Select((column, index) => new XElement(headers[index], column))))); 

xml.Save(@"C:\xmlout.xml"); 
+0

¿Hay alguna forma de convertir este ejemplo a JSON? – Alao

3

Escribí una clase que se deriva del fragmento de Vlax. Además, proporcioné una prueba unitaria para documentar el flujo de trabajo.

Test Unit:

[TestMethod] 
public void convert_csv_to_xml() 
{ 
    // Setup 
    var csvPath = @"Testware\vendor.csv"; 
    var xmlPath = @"Testware\vendor.xml"; 

    // Test 
    var success = DocumentConverter.Instance.CsvToXml(csvPath, xmlPath); 

    // Verify 
    var expected = File.Exists(xmlPath) && success; 
    Assert.AreEqual(true, expected); 
} 

CSV a XML:

public class DocumentConverter 
{ 
    #region Singleton 
    static DocumentConverter _documentConverter = null; 

    private DocumentConverter() { } 

    public static DocumentConverter Instance 
    { 
     get 
     { 
      if (_documentConverter == null) 
      { 
       _documentConverter = new DocumentConverter(); 
      } 

      return _documentConverter; 
     } 
    } 
    #endregion 

    public bool CsvToXml(string sourcePath, string destinationPath) 
    { 
     var success = false; 

     var fileExists = File.Exists(sourcePath); 

     if (!fileExists) 
     { 
      return success; 
     } 

     var formatedLines = LoadCsv(sourcePath); 
     var headers = formatedLines[0].Split(',').Select(x => x.Trim('\"').Replace(" ", string.Empty)).ToArray(); 

     var xml = new XElement("VendorParts", 
      formatedLines.Where((line, index) => index > 0). 
       Select(line => new XElement("Part", 
        line.Split(',').Select((field, index) => new XElement(headers[index], field))))); 

     try 
     { 
      xml.Save(destinationPath); 

      success = true; 
     } 
     catch (Exception ex) 
     { 
      success = false; 

      var baseException = ex.GetBaseException(); 
      Debug.Write(baseException.Message); 
     } 

     return success; 
    } 

    private List<string> LoadCsv(string sourcePath) 
    { 
     var lines = File.ReadAllLines(sourcePath).ToList(); 

     var formatedLines = new List<string>(); 

     foreach (var line in lines) 
     { 
      var formatedLine = line.TrimEnd(','); 
      formatedLines.Add(formatedLine); 
     } 
     return formatedLines; 
    } 
} 

NOTA:

extendí la solución de vlax mediante la eliminación de una coma al final de cada una de las Entradas de línea CSV que causaron una excepción de tiempo de ejecución ba sed en un índice fuera de límites en relación con el encabezado de columna.

+1

¡excelente implementación! – LordTitiKaka