如何格式化Windows Forms C#中DataGridView生成的XML文件
如何自定义DataTable导出XML的层级结构(Windows Forms)
刚接触Windows Forms才两周,我已经成功把DataGridView里的数据导出成XML文件了,但生成的XML结构完全不是我想要的样子。下面是我当前的输出、期望的目标格式,还有我现在用的代码,麻烦各位大佬帮忙看看怎么调整!
当前生成的XML
<?xml version="1.0" standalone="yes"?> <DocumentElement> <itemstable> <ProcessName>batchmnt.exe</ProcessName> <ProcessPID>DDD</ProcessPID> <ProcessFileName>mark</ProcessFileName> <Operation>WriteFile</Operation> <ProcessLength>3</ProcessLength> <ProcessPath>mark</ProcessPath> <ProcessKey>batchmnt.exe|DDD|mark|WriteFile</ProcessKey> </itemstable> </DocumentElement>
期望的XML格式
<Msg Date ="" Time=""> <Layer Name="Core"> <SourceLayer Name="PMC"> <Message ProcessName="" PID ="" FileName="" Operation="" Length="" Path=""> </Message> </SourceLayer> </Layer> </Msg>
现有实现代码
private void SaveXML() { string filename = ""; SaveFileDialog sfd = new SaveFileDialog { Filter = "XML (*.xml)|*.xml", FileName = "" }; if (sfd.ShowDialog() == DialogResult.OK) { filename = sfd.FileName; Deleteifexists(filename); DataTable dt = new DataTable("itemstable"); for (int i = 0; i < dataGridView1.ColumnCount; i++) { dt.Columns.Add(dataGridView1.Columns[i].Name, typeof(System.String)); } DataRow myrow; int icols = dataGridView1.Columns.Count; foreach (DataGridViewRow drow in this.dataGridView1.Rows) { myrow = dt.NewRow(); for (int i = 0; i <= icols - 1; i++) { myrow[i] = drow.Cells[i].Value; } dt.Rows.Add(myrow); } dt.WriteXml(filename); } }
解决方案:手动构建XML结构
DataTable.WriteXml()方法默认会生成扁平化的节点结构,没法直接生成你要的层级嵌套格式。所以我们可以改用XDocument(属于System.Xml.Linq命名空间)来手动构建符合要求的XML。
步骤如下:
- 首先在项目里引用
System.Xml.Linq命名空间(如果还没加的话); - 替换原来
dt.WriteXml(filename)的部分,改成手动创建XML节点的逻辑; - 循环DataGridView的每一行数据,把对应的值映射到
Message节点的属性上。
修改后的完整代码:
using System.Xml.Linq; // 记得加这个命名空间 private void SaveXML() { string filename = ""; SaveFileDialog sfd = new SaveFileDialog { Filter = "XML (*.xml)|*.xml", FileName = "" }; if (sfd.ShowDialog() == DialogResult.OK) { filename = sfd.FileName; Deleteifexists(filename); // 创建XML文档的根节点Msg,设置Date和Time为当前时间 var doc = new XDocument( new XDeclaration("1.0", "utf-8", "yes"), new XElement("Msg", new XAttribute("Date", DateTime.Now.ToString("yyyy-MM-dd")), new XAttribute("Time", DateTime.Now.ToString("HH:mm:ss")), new XElement("Layer", new XAttribute("Name", "Core"), new XElement("SourceLayer", new XAttribute("Name", "PMC") ) ) ) ); // 获取SourceLayer节点,用来添加Message子节点 var sourceLayer = doc.Descendants("SourceLayer").FirstOrDefault(); if (sourceLayer == null) return; // 循环DataGridView的每一行,创建Message节点 foreach (DataGridViewRow drow in this.dataGridView1.Rows) { // 跳过空行 if (drow.IsNewRow) continue; var message = new XElement("Message", new XAttribute("ProcessName", drow.Cells["ProcessName"].Value?.ToString() ?? ""), new XAttribute("PID", drow.Cells["ProcessPID"].Value?.ToString() ?? ""), new XAttribute("FileName", drow.Cells["ProcessFileName"].Value?.ToString() ?? ""), new XAttribute("Operation", drow.Cells["Operation"].Value?.ToString() ?? ""), new XAttribute("Length", drow.Cells["ProcessLength"].Value?.ToString() ?? ""), new XAttribute("Path", drow.Cells["ProcessPath"].Value?.ToString() ?? "") ); sourceLayer.Add(message); } // 保存XML到文件 doc.Save(filename); } }
说明
- 我把
Msg节点的Date和Time设置成了当前系统时间,你可以根据需要改成其他值; - 代码里加了空值判断(
?? ""),避免单元格为空时抛出异常; - 如果你的DataGridView有多行数据,每一行都会生成一个对应的
Message节点嵌套在SourceLayer下面。
内容的提问来源于stack exchange,提问作者Mark O Shea
相关产品推荐
相关产品推荐

