在系統集成、數據交換、配置持久化等場景中,DataTable / DataSet 與 XML 的雙向轉換是高頻需求。.NET Framework 內置 WriteXml / ReadXml 方法已提供基礎支持,但實際項目中常需處理編碼、流管理、異常捕獲等細節。本文提供兩個生產級封裝方法,並說明關鍵優化點。
///
/// 將 DataTable 序列化為 UTF-8 XML 字符串
///
public static string ConvertDataTableToXml(DataTable dataTable)
{
if (dataTable == null) return string.Empty;
using (var ms = new MemoryStream())
using (var writer = new XmlTextWriter(ms, Encoding.UTF8))
{
writer.Formatting = Formatting.Indented; // 可讀性輸出
dataTable.WriteXml(writer);
writer.Flush();
return Encoding.UTF8.GetString(ms.ToArray()).Trim();
}
}
///
/// 將 XML 字符串反序列化為 DataSet
///
public static DataSet ConvertXmlToDataSet(string xmlData)
{
if (string.IsNullOrWhiteSpace(xmlData)) return null;
using (var sr = new StringReader(xmlData))
using (var reader = new XmlTextReader(sr))
{
reader.DtdProcessing = DtdProcessing.Ignore; // 安全:禁用 DTD 防止 XXE
var ds = new DataSet();
ds.ReadXml(reader);
return ds;
}
}
| 原始代碼問題 | 優化方案 | 收益 |
|---|---|---|
| 手動管理 Stream/Reader 生命週期 | using 塊自動釋放 | 杜絕資源洩漏 |
編碼硬編碼 Encoding.Default | 統一使用 Encoding.UTF-8 | 跨平台一致性,避免中文亂碼 |
| 無異常信息記錄 | 拋出異常或記錄日誌 | 便於排查數據格式錯誤 |
| XmlTextReader 預設啟用 DTD | DtdProcessing.Ignore | 防範 XML 外部實體注入 (XXE) 攻擊 |
返回 String.Empty/null 混用 | 統一語義:無效輸入返回 null,空表返回空 XML | 調用端判斷更直觀 |
// 序列化
var dt = GetUserDataTable();
string xml = ConvertDataTableToXml(dt);
SaveToFile(xml, "users.xml");
// 反序列化
string xmlContent = File.ReadAllText("users.xml", Encoding.UTF8);
DataSet ds = ConvertXmlToDataSet(xmlContent);
if (ds != null && ds.Tables.Count > 0)
{
BindGrid(ds.Tables[0]);
}
WriteXml(..., XmlWriteMode.WriteSchema) 同時輸出 XSD,反序列化時自動恢復類型與約束。XmlWriter 分塊寫入文件,避免內存壓力。XmlReader.CreateAsync / XmlWriter.CreateAsync 實現非阻塞 I/O。這兩個靜態方法可直接放入通用工具類(如 XmlHelper),滿足絕大多數企業級項目中 DataTable 與 XML 互轉的需求,代碼簡潔、健壯、安全。