【问题标题】:Convert CSV file to XML将 CSV 文件转换为 XML
【发布时间】:2011-03-05 10:07:59
【问题描述】:

我需要将 CSV 转换为 XML 文档。到目前为止,我看到的示例都显示了如何在 CSV 中使用固定数量的列来执行此操作。

到目前为止,我使用 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());

这是针对固定数量的列,但我的 .CSV 在每行有不同数量的列。

根据 .CSV 的每一行中有多少单词(列),您如何将某种循环放入其中?

谢谢

【问题讨论】:

    标签: c# xml csv


    【解决方案1】:
    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");
    

    输入:

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

    输出:

    <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>
    

    【讨论】:

    • 非常接近。但是我需要将每行上的每个单词都分开,用 ; 分隔。因此,输出 XML 将如下所示: wordwordwordwordwordwordword 我几乎和我发布的代码一样,但我只得到每行的第一个单词。所以我需要添加某种循环,为每行上的每个单词添加一个 Column 元素,由 ;
    • @Soeren:我的解决方案不就是这样吗?我添加了一个示例以进行说明。
    • 这很好用。 line.Split(';') 部分不在第一个示例中,我尝试自己添加它。我只是不知道如何添加它。我需要再研究一下这个 LINQ 的东西。感谢您的帮助。
    • 很棒的帖子...我用了一些零碎的东西,它完美地工作
    • 回复有点晚,但是如果您的列可以在带引号的列中包含分隔符,请注意 string .split() 不会注意带引号的字符串。示例: var x = "\"Quoted;string\""; var words = x.Split(';');词[0]; // "Quoted words[1]; // "string" 所以,如果你的分隔符是一个普通字符,你会有额外的数据列。
    【解决方案2】:

    如果您想使用标题作为元素名称:

    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");
    

    【讨论】:

    • 有没有办法将此示例转换为 JSON?
    【解决方案3】:

    我编写了一个派生自 Vlax 的 sn-p 的类。 此外,我还提供了一个单元测试来记录工作流程。

    单元测试:

    [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 转 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;
        }
    }
    

    注意:

    我扩展了 Vlax 的解决方案,删除了导致运行时异常的每个 CSV 行条目的尾随逗号,该异常基于与列标题相关的索引超出范围。

    【讨论】:

    • 伟大的实现!
    • 代码工作正常,但如果我的 csv 中有逗号分隔值,它就无法工作。
    【解决方案4】:

    Cinchoo ETL - 一个开源库,只需几行代码即可轻松将 CSV 转换为 Xml

    对于示例 CSV:

    string csv = @"Id, Name, City
    1, Tom, NY
    2, Mark, NJ
    3, Lou, FL
    4, Smith, PA
    5, Raj, DC
    ";
    
    StringBuilder sb = new StringBuilder();
    
    using (var p = ChoCSVReader.LoadText(csv)
        .WithFirstLineHeader()
        )
    {
        using (var w = new ChoXmlWriter(sb)
            .Configure(c => c.RootName = "Employees")
            .Configure(c => c.NodeName = "Employee")
            )
            w.Write(p);
    }
    
    Console.WriteLine(sb.ToString());
    

    输出 Xml:

    <Employees>
      <Employee>
        <Id>1</Id>
        <Name>Tom</Name>
        <City>NY</City>
      </Employee>
      <Employee>
        <Id>2</Id>
        <Name>Mark</Name>
        <City>NJ</City>
      </Employee>
      <Employee>
        <Id>3</Id>
        <Name>Lou</Name>
        <City>FL</City>
      </Employee>
      <Employee>
        <Id>4</Id>
        <Name>Smith</Name>
        <City>PA</City>
      </Employee>
      <Employee>
        <Id>5</Id>
        <Name>Raj</Name>
        <City>DC</City>
      </Employee>
    </Employees>
    

    查看 CodeProject 文章以获得更多帮助。

    免责声明:我是这个库的作者。

    【讨论】:

      【解决方案5】:

      这里提供了一个不使用嵌套LINQ的解决方案,更容易理解。

      • 使用 Linq to Xml。
      • 支持不同的分隔符(const)
      • 支持每一行有不同的切片

      input.csv的内容:

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

      流程代码:

      Program.cs

      using System;
      using System.IO;
      using System.Linq;
      using System.Xml.Linq;
      
      namespace CSVtoXML
      {
          class Program
          {
              private static void AddContentForEachLine(string line, ref XElement xmlTree)
              {
                  var currentTree = new XElement("Item");
                  const string delimiter = ",";     // Can be changed based on the actual situation
                  string[] slices = line.Split(delimiter);
      
                  for (int i = 0; i < slices.Count(); i++)
                      currentTree.Add(new XElement($"Column{i}", slices[i].ToString()));
      
                  xmlTree.Add(currentTree);
              }
      
              static void Main(string[] args)
              {
                  var basePath = Environment.CurrentDirectory;
                  var lines = File.ReadAllLines(Path.Combine(basePath, "../../..", @"input.csv"));
      
                  var xmlTree = new XElement("TopElement");
      
                  foreach (var line in lines)
                  {
                      AddContentForEachLine(line, ref xmlTree);
                  }
      
                  xmlTree.Save(Path.Combine(basePath, "../../..", @"output.xml"));
              }
          }
      }
      

      运行代码后,结果如下:

      <?xml version="1.0" encoding="utf-8"?>
      <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>
      


      可以在此处查看此代码的完整 Visual Studio 解决方案: https://github.com/yanglr/dotnetInterview/tree/master/CSVtoXML.

      【讨论】:

        猜你喜欢
        • 2015-10-28
        • 2014-11-22
        • 2017-04-18
        • 1970-01-01
        • 1970-01-01
        • 2020-03-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多