
在 C# 中把 Excel 转成 XML,可能对应三种不同的输出:将整个工作簿保存为 XML 表格文件,按业务字段生成自定义 XML,或者借助 .NET 自带的 DataTable.WriteXml 序列化表格数据。三者用途不同,不能互相替代。
本教程使用 Spire.XLS for .NET 演示这三种做法。Spire.XLS for .NET 是一套独立的 Excel 读写库,运行环境无需安装 Microsoft Excel,也不依赖 Office Interop。你将学会导出整份工作簿、按业务结构生成自定义 XML,以及通过 DataTable 序列化数据,并了解每种输出的实际格式和导出时的数据类型处理方式。
快速导航
- Excel 转 XML 会得到哪几种 XML?
- 准备示例文档与环境
- 将整个工作簿导出为 XML
- 按业务结构导出指定数据
- 借助 DataTable.WriteXml 导出
- XLS、XLSX 与数据处理细节
- 常见问题
- 总结
1. Excel 转 XML 会得到哪几种 XML?
动手之前先确认接收方需要哪一种 XML。Excel 场景里常见的有三类:
| 类型 | 说明 | 适用场景 |
|---|---|---|
| XML Spreadsheet 2003(SpreadsheetML) | 用单个 XML 文件描述整个工作簿,包含 Workbook、Worksheet、Row、Cell 等元素 | 下游系统接受 Excel 2003 XML 表格 |
| Office Open XML(OOXML) | .xlsx 使用的格式,本质是 ZIP 包,内部由工作簿、工作表、样式等多个 XML 部件组成 | 需要读取或修改 XLSX 内部结构 |
| 自定义 XML | 元素名和层级由业务决定 | 对接 API、数据库导入或合作方指定的 XML 结构 |
根节点为 <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"> 的文件属于 XML Spreadsheet 2003。XLSX 则是 ZIP 容器,内部包含多个 XML 部件,二者不是一回事。由于 Excel 文档里都把它们称作 XML,实际使用时很容易混淆。
下面的内容分别对应这三种输出。选择哪一种,取决于接收方读取的是工作簿结构、业务字段,还是标准表格。
2. 准备示例文档与环境
安装 Spire.XLS for .NET
在项目中通过 NuGet 安装:
dotnet add package Spire.XLS
引入命名空间
using Spire.Xls;
本文采用下面的 Excel 文档作为操作示例。工作簿包含 Orders 和 Summary 两个工作表,Orders 表记录订单号、客户、区域、产品、数量、单价、金额、日期和状态。

XLS 与 XLSX 都通过 LoadFromFile() 加载,后续导出步骤相同。
3. 将整个工作簿导出为 XML
需要整份工作簿的 XML 表格时,加载文件后调用 Workbook.SaveAsXml():
using Spire.Xls;
using (Workbook workbook = new Workbook())
{
// 加载 Excel 工作簿
workbook.LoadFromFile("SalesOrders.xlsx");
// 将工作簿保存为 XML 表格
workbook.SaveAsXml("output.xml");
}
SaveToFile("output.xml", FileFormat.XML) 与 SaveAsXml() 的输出一致,按代码可读性选择即可。
输出格式是 XML Spreadsheet 2003,与 OOXML 包无关。实际文件的开头如下:
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:x="urn:schemas-microsoft-com:office:excel">
<ss:Styles>...</ss:Styles>
<ss:Worksheet ss:Name="Orders">
<ss:Table ss:DefaultColumnWidth="48.75">
<Row ss:Index="1">
<Cell ss:Index="1"><Data ss:Type="String">OrderID</Data></Cell>
<Cell ss:Index="2"><Data ss:Type="String">Customer</Data></Cell>
<Cell ss:Index="3"><Data ss:Type="String">Region</Data></Cell>
<Cell ss:Index="4"><Data ss:Type="String">Product</Data></Cell>
</Row>
...
导出结果在编辑器中打开时,可以看到 Workbook 根节点以及 ss:Worksheet、Row、Cell、Data 等元素:

需要读回工作簿时使用 LoadFromXml();LoadFromFile() 则用于 XLS 和 XLSX 工作簿。
using (Workbook workbook = new Workbook())
{
// 加载 XML Spreadsheet 2003 文件
workbook.LoadFromXml("output.xml");
// 之后可访问 workbook.Worksheets
}
导出会连同样式和单元格格式一起写入,因此生成的 XML 描述的是完整的工作表,而不只是数据。
4. 按业务结构导出指定数据
整表导出方便,但多数集成需要自己的元素名。自定义 XML 通常只取一个区域,再按固定字段输出。示例工作簿中 Orders 表的部分数据如下:
| 订单号 | 金额 | 日期 |
|---|---|---|
| DD-1001 | 3897.00 | 2026-10-01 |
| DD-1002 | 1645.00 | 2026-10-02 |
| DD-1003 | 2598.00 | 2026-10-03 |
目标结构:
<?xml version="1.0" encoding="utf-8"?>
<orders>
<order>
<id>DD-1001</id>
<amount>3897.00</amount>
<orderDate>2026-10-01</orderDate>
</order>
<order>
<id>DD-1002</id>
<amount>1645.00</amount>
<orderDate>2026-10-02</orderDate>
</order>
<order>
<id>DD-1003</id>
<amount>2598.00</amount>
<orderDate>2026-10-03</orderDate>
</order>
</orders>
做法是先把区域导出为 DataTable,再用 XmlWriter 写 XML:
using System;
using System.Data;
using System.Globalization;
using System.Text;
using System.Xml;
using Spire.Xls;
using (Workbook workbook = new Workbook())
{
workbook.LoadFromFile("SalesOrders.xlsx");
Worksheet sheet = workbook.Worksheets["Orders"];
var options = new ExportTableOptions
{
ExportColumnNames = true,
KeepDataType = true,
KeepDataFormat = false,
ComputedFormulaValue = true
};
// AllocatedRange 只包含实际使用的单元格
DataTable table = sheet.ExportDataTable(sheet.AllocatedRange, options);
var settings = new XmlWriterSettings
{
Indent = true,
Encoding = new UTF8Encoding(false)
};
using (XmlWriter writer = XmlWriter.Create("orders-custom.xml", settings))
{
writer.WriteStartDocument();
writer.WriteStartElement("orders");
foreach (DataRow row in table.Rows)
{
writer.WriteStartElement("order");
writer.WriteElementString("id",
Convert.ToString(row["OrderID"], CultureInfo.InvariantCulture));
string amount = row.IsNull("Amount")
? string.Empty
: Convert.ToDecimal(row["Amount"], CultureInfo.InvariantCulture)
.ToString("F2", CultureInfo.InvariantCulture);
writer.WriteElementString("amount", amount);
string orderDate = row.IsNull("OrderDate")
? string.Empty
: Convert.ToDateTime(row["OrderDate"], CultureInfo.InvariantCulture)
.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
writer.WriteElementString("orderDate", orderDate);
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
}
AllocatedRange 只覆盖实际使用的单元格,导出的记录与数据量一致。若传入固定区域,例如 sheet.Range["A1:C100"],数据下方的空行也会被包含;使用固定区域时,需要跳过所有字段都为空的记录。
两个选项决定输出形态。KeepDataType 为 true 且 KeepDataFormat 为 false 时,Amount 保持 decimal,OrderDate 保持 DateTime。若将 KeepDataFormat 设为 true,则改取单元格的显示文本,例如 2026/10/29。XmlWriter 会自动转义单元格中的 &、<、>,输出始终是合法 XML。
源列中的数字若以文本存储,或日期是普通字符串,需要先显式转换。在固定区域性(InvariantCulture)下,Convert.ToDecimal 期望的格式是 1250.50,而不是 1,250.50。
这种方式只写出选中的数据。若同时需要合并单元格、列宽和字体,使用第 3 节的工作簿导出。
写出后的 orders-custom.xml:

5. 借助 DataTable.WriteXml 导出
接收方接受标准表结构 XML 时,DataTable.WriteXml() 可以省去手写元素:
using System.Data;
using Spire.Xls;
using (Workbook workbook = new Workbook())
{
workbook.LoadFromFile("SalesOrders.xlsx");
Worksheet sheet = workbook.Worksheets[0];
var options = new ExportTableOptions
{
ExportColumnNames = true,
KeepDataType = true,
KeepDataFormat = false
};
DataTable table = sheet.ExportDataTable(sheet.AllocatedRange, options);
table.TableName = "Orders";
table.WriteXml("orders.xml", XmlWriteMode.IgnoreSchema);
}
输出根节点为 DocumentElement,每行对应一个 Orders 元素:
<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<Orders>
<OrderID>DD-1001</OrderID>
<Customer>北京华信科技有限公司</Customer>
<Region>华北</Region>
...
<Amount>3897</Amount>
<OrderDate>2026-10-01T00:00:00+08:00</OrderDate>
<Status>已发货</Status>
</Orders>
</DocumentElement>
DataTable 输出,一行对应一个 Orders 元素:

日期会带本地时区偏移,同一份工作簿在不同时区的服务器上生成的字符串不同。若接收方要求 UTC,需要先做归一化。
需要换根节点时,用 DataSet 再包一层。表名要先改掉,否则会出现 Orders 嵌套 Orders 的结构:
table.TableName = "Order";
var dataSet = new DataSet("Orders");
dataSet.Tables.Add(table);
dataSet.WriteXml("orders-dataset.xml", XmlWriteMode.IgnoreSchema);
输出使用设定的根与记录名:
<?xml version="1.0" standalone="yes"?>
<Orders>
<Order>
<OrderID>DD-1001</OrderID>
...
XmlWriteMode.WriteSchema 会在文档中加入 XSD 架构,接收方需要读取架构时再使用。
导出相关的更多用法见用 C# 读取 Excel 为 DataTable 的详细教程。
6. XLS、XLSX 与数据处理细节
XLS 与 XLSX
两种格式都通过 LoadFromFile() 加载,输出格式与输入扩展名无关。用 SaveAsXml() 导出 XLSX 时,得到的是一个 XML 表格文档;原文件内部的各个 XML 部件属于另一种格式。先确定输出格式,再选择方法。需要直接处理 XLSX 内部的 Open XML 部件时,可参考 C#/VB.NET 将 Excel 转换为 Open XML 或将 Open XML 转换为 Excel。
日期与数字
Excel 用数字存储日期,再通过格式显示。经 DataTable 导出时,需要决定取原始值还是显示文本。跨系统交换建议保留原始值,写出时再格式化,例如前面的 yyyy-MM-dd。
公式
ComputedFormulaValue 设为 true 时写出计算结果;接收方需要公式本身时设为 false。
表头与空单元格
ExportColumnNames 设为 true 会把首行作为列名。选中区域应排除标题、备注和空行。空值写成省略元素、空元素还是显式 null 标记,需要提前与接收方确认。
多工作表
工作簿导出会写出全部工作表,区域导出只写一个。需要从多个工作表生成自定义 XML 时,遍历集合,为每个工作表写一个父元素:
using (XmlWriter writer = XmlWriter.Create("workbook-custom.xml", settings))
{
writer.WriteStartDocument();
writer.WriteStartElement("workbook");
foreach (Worksheet sheet in workbook.Worksheets)
{
DataTable table = sheet.ExportDataTable(sheet.AllocatedRange, options);
writer.WriteStartElement("sheet");
writer.WriteAttributeString("name", sheet.Name);
foreach (DataRow row in table.Rows)
{
writer.WriteStartElement("row");
foreach (DataColumn column in table.Columns)
{
writer.WriteStartElement("field");
writer.WriteAttributeString("name", column.ColumnName);
writer.WriteString(Convert.ToString(row[column], CultureInfo.InvariantCulture));
writer.WriteEndElement();
}
writer.WriteEndElement();
}
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
这段代码沿用前面的 settings 和 options 对象。
列名写成属性而不是元素名是有意为之。XML 元素名不能包含空格,也不能以数字开头,Order ID 或 2026 Total 这类表头需要先转成合法名称;属性写法可以直接接受任意表头。
只导出有数据的工作表时,在写 <sheet> 前判断 table.Rows.Count 即可。
多工作表输出,保留工作表名与列名:

大文件
数据量很大时,按行分块读取,或在遍历单元格的同时直接用 XmlWriter 写出,避免一次性把整个区域载入内存。
若源数据来自 CSV,可参考使用 C# 将 CSV 转为 XML。
7. 常见问题
如何在 C# 中把 XLSX 转成 XML?
用 Workbook.LoadFromFile() 加载文件,再调用 SaveAsXml(),得到 XML Spreadsheet 2003 文档。需要自定义元素名时,改为把区域导出为 DataTable,再用 XmlWriter 或 DataTable.WriteXml() 写出。
SaveAsXml() 生成的是 Office Open XML 吗?
SaveAsXml() 生成 XML Spreadsheet 2003。输出使用 urn:schemas-microsoft-com:office:spreadsheet 命名空间和 Workbook 根节点,可据此识别。Office Open XML 是 .xlsx 的包格式,属于另一种处理方式。
只导出某一个工作表怎么做?
用 Worksheet.ExportDataTable() 取出该工作表的数据,再序列化。工作簿级的 SaveAsXml() 会写出整份工作簿。
能自定义元素名吗?
可以,使用 XmlWriter。根节点、记录元素、字段名、嵌套层级和取值格式都可以自行定义。DataTable.WriteXml() 写起来更快,但结构固定为表结构。
XLS 文件也能这样处理吗?
可以。XLS 与 XLSX 都用 LoadFromFile() 加载,XLS 转 XML 与 XLSX 转 XML 的导出步骤相同。
8. 总结
Excel 转 XML 的关键,是先确定接收方需要哪种 XML,再选择对应接口。使用 Spire.XLS for .NET 时,SaveAsXml() 面向整份工作簿,输出 XML Spreadsheet 2003;XmlWriter 面向自定义结构,字段和层级完全可控;DataTable.WriteXml() 面向标准表结构,一行对应一个元素。
三种输出的差别体现在内容范围上。XML Spreadsheet 2003 保留工作簿格式和结构,自定义 XML 只写选中的字段,DataTable 方式保留表结构但根节点和记录名固定。把它们与 XLSX 内部的 XML 部件区分开,可以避免大部分对接问题。
导出时保持数据类型:KeepDataType 设为 true,KeepDataFormat 设为 false;区域使用 AllocatedRange;空值的写法提前确定。
如果需要在真实业务环境中测试 Spire.XLS for .NET,可以申请临时许可证。







