如何使用C#将XML文件转换为CSV?现有代码报错寻求解决方案
先帮你逐个解决编译报错,再修正XML解析和CSV生成的核心逻辑:
一、先搞定编译报错
你的三个报错都是C#版本和基础语法问题,先把这些理顺:
"Feature 'top-level statements' is not available in C# 7.3..."
顶级语句(直接写在类/命名空间外面的代码)是C#9.0才新增的特性。解决方法二选一:- 打开项目属性 → 生成 → 高级 → 语言版本,选择C#9.0或更高(比如最新的C#12)
- 如果不想升级C#版本,把所有代码放到控制台应用的
Main方法里,用传统的程序结构编写。
"Top-level statements must precede namespace and type declarations"
顶级语句的位置规则是:必须放在所有类、命名空间声明的前面。你现在先写了ReportData类,再写using代码块,顺序反了。要么把using块移到类的前面,要么把代码放到Main方法里。"A new expression requires an argument list..."
纯粹的语法写错了:List<string> list = new List<string>;少了括号,应该改成List<string> list = new List<string>();
二、修正XML解析与CSV生成逻辑
你的代码里的实体类和XML结构完全不匹配,导致反序列化必然失败,而且CSV生成的逻辑也没对应上XML里的数据结构。下面是完整的修复方案:
第一步:创建匹配XML结构的实体类
根据你提供的XML内容,我已经整理好对应的实体类(也可以用Visual Studio的「编辑→粘贴特殊→粘贴XML为类」自动生成):
using System.Collections.Generic; using System.Xml.Serialization; [XmlRoot("XML")] public class XmlRoot { [XmlElement("XMLMsgsRs")] public XmlMsgsRs XmlMsgsRs { get; set; } } public class XmlMsgsRs { [XmlElement("GeneralSummaryReportQueryRs")] public GeneralSummaryReportQueryRs GeneralSummaryReportQueryRs { get; set; } } public class GeneralSummaryReportQueryRs { [XmlElement("ReportRet")] public ReportRet ReportRet { get; set; } } public class ReportRet { [XmlElement("ColDesc")] public List<ColDesc> ColDescs { get; set; } [XmlElement("ReportData")] public ReportData ReportData { get; set; } } public class ColDesc { [XmlElement("ColTitle")] public ColTitle ColTitle { get; set; } } public class ColTitle { [XmlAttribute("value")] public string Value { get; set; } } public class ReportData { [XmlElement("DataRow")] public List<DataRow> DataRows { get; set; } } public class DataRow { [XmlElement("ColData")] public List<ColData> ColDatas { get; set; } } public class ColData { [XmlAttribute("colID")] public string ColId { get; set; } [XmlAttribute("value")] public string Value { get; set; } }
第二步:编写正确的转换代码
这段代码会正确读取XML,提取表头和数据,还处理了CSV的特殊字符(比如逗号、引号),避免生成的CSV在Excel里解析出错:
using System.IO; using System.Xml.Serialization; using System.Linq; // 读取XML文件并反序列化 var serializer = new XmlSerializer(typeof(XmlRoot)); XmlRoot xmlData; using (var fs = new FileStream(@"C:\inventory.xml", FileMode.Open)) { xmlData = (XmlRoot)serializer.Deserialize(fs); } // 提取CSV表头(从ColDesc的ColTitle中获取) var headers = xmlData.XmlMsgsRs.GeneralSummaryReportQueryRs.ReportRet.ColDescs .Select(c => c.ColTitle?.Value ?? string.Empty) .ToList(); // 准备CSV行列表,先加入表头 var csvRows = new List<string>(); csvRows.Add(FormatCsvLine(headers)); // 遍历所有DataRow,提取数据并按列顺序排列 foreach (var dataRow in xmlData.XmlMsgsRs.GeneralSummaryReportQueryRs.ReportRet.ReportData.DataRows) { // 按colID从小到大排序ColData,确保和表头顺序一致 var sortedColDatas = dataRow.ColDatas.OrderBy(c => int.Parse(c.ColId)).ToList(); var rowValues = sortedColDatas.Select(c => c.Value ?? string.Empty).ToList(); // 补充缺失的列(比如有的DataRow可能少了colID=6的Physical Count数据) while (rowValues.Count < headers.Count) { rowValues.Add(string.Empty); } csvRows.Add(FormatCsvLine(rowValues)); } // 写入CSV文件 File.WriteAllLines(@"C:\csvFile.csv", csvRows); // 辅助方法:格式化CSV行,处理特殊字符 string FormatCsvLine(List<string> values) { return string.Join(",", values.Select(v => { if (v.Contains(",") || v.Contains("\"") || v.Contains("\n")) { // 如果内容包含逗号、引号或换行,用双引号包裹,内部的双引号替换为两个双引号 return $"\"{v.Replace("\"", "\"\"")}\""; } return v; })); }
三、额外注意事项
- 尽量避免把文件写到C盘根目录,可能需要管理员权限,建议先放到文档目录测试
- 如果XML里有更多TextRow或其他节点,可以根据需求调整实体类和数据提取逻辑
- 这段代码会自动处理CSV的格式问题,生成的文件可以直接用Excel打开
内容的提问来源于stack exchange,提问作者Zeke Medina

