如何从XML文件创建CSV文件

时间:2017-12-12 09:54:14

标签: c# xml csv

我是C#的新手。在我的项目中,我需要创建一个csv文件,该文件将从xml数据中获取数据。现在,我可以从XML获取数据,并在looger中打印来自xml的某些特定属性。但我不知道如何将我的数据存储到CSV文件中以获取特定的属性。

这是我创建CSV文件所需的XML文件。

    <?xml version="1.0" encoding="utf-8"?>
<tlp:WorkUnits xmlns:tlp="http://www.timelog.com/XML/Schema/tlp/v4_4"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.timelog.com/XML/Schema/tlp/v4_4 http://www.timelog.com/api/xsd/WorkUnitsRaw.xsd">
  <tlp:WorkUnit ID="130">
    <tlp:EmployeeID>3</tlp:EmployeeID>
    <tlp:AllocationID>114</tlp:AllocationID>
    <tlp:TaskID>239</tlp:TaskID>
    <tlp:ProjectID>26</tlp:ProjectID>
    <tlp:ProjectName>LIK Template</tlp:ProjectName>
    <tlp:CustomerId>343</tlp:CustomerId>
    <tlp:CustomerName>Lekt Corp Inc.</tlp:CustomerName>
    <tlp:IsBillable>1</tlp:IsBillable>
    <tlp:ApprovedStatus>0</tlp:ApprovedStatus>
    <tlp:LastModifiedBy>AL</tlp:LastModifiedBy>
  </tlp:WorkUnit>

我的代码我在logger中得到这个值。但我不知道如何创建一个按顺序存储该值的csv文件。

被修改

   namespace TimeLog.ApiConsoleApp
{
    /// <summary>
    /// Template class for consuming the reporting API
    /// </summary>
    public class ConsumeReportingApi
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(ConsumeReportingApi));

        public static void Consume()
        {
            if (ServiceHandler.Instance.TryAuthenticate())
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info("Successfully authenticated on reporting API");
                }

                var customersRaw = ServiceHandler.Instance.Client.GetWorkUnitsRaw(ServiceHandler.Instance.SiteCode,
                     ServiceHandler.Instance.ApiId,
                     ServiceHandler.Instance.ApiPassword,
                     WorkUnit.All,
                     Employee.All,
                     Allocation.All,
                     Task.All,
                     Project.All,
                     Department.All,
                     DateTime.Now.AddDays(-5).ToString(),
                     DateTime.Now.ToString()
                  );



                if (customersRaw.OwnerDocument != null)
                {
                    var namespaceManager = new XmlNamespaceManager(customersRaw.OwnerDocument.NameTable);
                    namespaceManager.AddNamespace("tlp", "http://www.timelog.com/XML/Schema/tlp/v4_4");
                    var workUnit = customersRaw.SelectNodes("tlp:WorkUnit", namespaceManager);

                    var output = new StringBuilder();
                    output.AppendLine("AllocationID,ApprovedStatus,CustomerId,CustomerName,EmployeeID");
                    if (workUnit != null)
                    {

                       foreach (XmlNode customer in workUnit)

                        {
                            var unit = new WorkUnit();
                            var childNodes = customer.SelectNodes("./*");

                            if (childNodes != null)
                            {


                                foreach (XmlNode childNode in childNodes)
                                {
                                    if (childNode.Name == "tlp:EmployeeID")
                                    {
                                        unit.EmployeeID = Int32.Parse(childNode.InnerText);
                                    }
                                    if (childNode.Name == "tlp:EmployeeFirstName")
                                    {
                                        unit.EmployeeFirstName = childNode.InnerText;
                                    }
                                    if (childNode.Name == "tlp:EmployeeLastName")
                                    {
                                        unit.EmployeeLastName = childNode.InnerText;
                                    }

                                    if (childNode.Name == "tlp:AllocationID")
                                    {
                                        unit.AllocationID = Int32.Parse(childNode.InnerText);
                                    }

                                    if (childNode.Name == "tlp:TaskName")
                                    {
                                        unit.TaskName = childNode.InnerText;
                                    }


                                }                             
                           }
                            output.AppendLine($"{unit.EmployeeID},{unit.EmployeeFirstName},{unit.EmployeeLastName},{unit.AllocationID},{unit.TaskName}");
                            //Console.WriteLine("---");

                        }

                        Console.WriteLine(output.ToString());
                        File.WriteAllText("c:\\...\\WorkUnits.csv", output.ToString());

                    }
                }

                else
                {
                    if (Logger.IsWarnEnabled)
                    {
                        Logger.Warn("Failed to authenticate to reporting API");
                    }
                }
            }
        }
    }
}

5 个答案:

答案 0 :(得分:1)

假设您将XML数据放入List

 StringBuilder str = new StringBuilder();

  foreach (var fin list.ToList())
  {
        str.Append(fin.listfield.ToString() + ",");

  }

创建一个新行:

str.Replace(",", Environment.NewLine, str.Length - 1, 1);

保存:

string filename=(DirectoryPat/filename.csv");
File.WriteAllText(Filename, str.ToString());

答案 1 :(得分:1)

您希望以正确的顺序将列写入CSV(当然),因此您需要按正确的顺序处理它们。两个选项:

中级

创建一个新类(我们称之为WorkUnit),其中包含要写入CSV的每个列的属性。为XML中的每个<tlp:WorkUnit>节点创建一个新实例,并在遇到正确的子节点时填充属性。处理完整个WorkUnit节点后,请按正确的顺序写出属性。

  var output = new StringBuilder();
  foreach (XmlNode customer in workUnit)
  {
       // fresh instance of the class that holds all columns (so all properties are cleared)
       var unit = new WorkUnit();
       var childNodes = customer.SelectNodes("./*");

       if (childNodes != null)
       {
            foreach (XmlNode childNode in childNodes)
            {
                if(childNode.Name== "tlp:EmployeeID")
                {
                     // employeeID node found, now write to the corresponding property:
                     unit.EmployeeId = childNode.InnerText;
                }
                // etc for the other XML nodes you are interested in
            }
            // all nodes have been processed for this one WorkUnit node
            // so write a line to the CSV
            output.AppendLine($"{unit.EmployeeId},{unit.AllocationId}, etc");
       }

按正确顺序阅读

不是使用foreach以它们出现的顺序遍历所有子节点,而是按照您想要的顺序搜索特定的子节点。然后,您可以按相同的顺序写出CSV。请注意,即使您没有找到某个子节点,仍然需要写出分隔符。

  var output = new StringBuilder();
  foreach (XmlNode customer in workUnit)
  {
      // search for value for first column (EmployeeID)
      var node = workUnit.SelectSingleNode("tlp:EmployeeID");
      if (node != null)
      {
         output.Append(node.InnerText).Append(',');
      }
      else
      {
         output.Append(','); // no content, but we still need a separator
      }
      // etc for the other columns

当然要注意包含分隔符的字符串值。

答案 2 :(得分:1)

试试这个:

var output = new StringBuilder();
output.AppendLine("AllocationID,ApprovedStatus,CustomerId,CustomerName,EmployeeID");
if (workUnit != null)
{
    foreach (XmlNode customer in workUnit)
    {
        var unit = new WorkUnit();
        var childNodes = customer.SelectNodes("./*");
        if (childNodes != null)
        {
            for (int i = 0; i<childNodes.Count; ++i)
            {
                XmlNode childNode = childNodes[i];
                if (childNode.Name == "tlp:EmployeeID")
                {
                    unit.EmployeeID = Int32.Parse(childNode.InnerText);
                }
                if (childNode.Name == "tlp:EmployeeFirstName")
                {
                    unit.EmployeeFirstName = childNode.InnerText;
                }
                if (childNode.Name == "tlp:EmployeeLastName")
                {
                    unit.EmployeeLastName = childNode.InnerText;
                }

                if (childNode.Name == "tlp:AllocationID")
                {
                    unit.AllocationID = Int32.Parse(childNode.InnerText);
                }

                if (childNode.Name == "tlp:TaskName")
                {
                    unit.TaskName = childNode.InnerText;
                }

                output.Append(childNode.InnerText);
                if (i<childNodes.Count - 1)
                    output.Append(",");
            }
            output.Append(Environment.NewLine);
        }
    }
    Console.WriteLine(output.ToString());
    File.WriteAllText("c:\\Users\\mnowshin\\projects\\WorkUnits.csv", output.ToString());
}

答案 3 :(得分:0)

您可以使用以下序列:

一个。反序列化(即从XML转换为C#对象)您的XML。

湾编写一个简单的循环来将数据写入文件。

这个序列的优点:

  • 您可以使用“可读”的数据/对象列表,您可以向其添加任何其他访问代码。
  • 如果您随时更改了XML架构,则可以非常轻松地维护代码。

解决方案

一个。 Desrialize:

  1. 复制XML文件内容。 注意 您应该在处理之前修改XML输入。您应该将WorkUnit节点加倍,以告诉Visual Studio您将在WorkUnits中嵌套此节点的列表节点
  2. 从Visual Studio菜单中选择编辑 - &gt;选择性粘贴 - &gt;将XML粘贴为类。
  3. 使用反序列化代码。

        var workUnitsNode = customersRaw.SelectSingleNode("tlp:WorkUnits", namespaceManager);
        XmlSerializer ser = new XmlSerializer(typeof(WorkUnits));
        WorkUnits workUnits = (WorkUnits)ser.Deserialize(workUnitsNode);
    

    湾写csv文件

        StringBuilder csvContent = new StringBuilder();
        // add the header line
        csvContent.AppendLine("AllocationID,ApprovedStatus,CustomerId,CustomerName,EmployeeID");
        foreach (var unit in workUnits.WorkUnit)
        {
            csvContent.AppendFormat(
                "{0}, {1}, {2}, {3}, {4}",
                new object[] 
                {
                    unit.AllocationID,
                    unit.ApprovedStatus,
                    unit.CustomerId,
                    unit.CustomerName,
                    unit.EmployeeID
                    // you get the idea
                });
            csvContent.AppendLine();
        }
    
        File.WriteAllText(@"G:\Projects\StackOverFlow\WpfApp1\WorkUnits.csv", csvContent.ToString());
    

答案 4 :(得分:0)

您可以使用Cinchoo ETL - 如果您有空间使用开源库

class

输出:

//using System.Linq;                                         // at the top of the file
//using KVP = System.Collections.Generic.KeyValuePair<string, double>;

KVP[] sums = result.Sites.Select(s => new KVP(s.SiteName, s.Actual.Sum())).ToArray();
// or List<KVP> sums = result.Sites.ConvertAll(s => new KVP(s.SiteName, s.Actual.Sum()));

免责声明:我是这个图书馆的作者。