不会自动创建你想要的 datatable 结构——它只按 xml 根节点和嵌套层级推断表名与关系,默认将所有子元素当列,且列类型fallback为string,命名空间、属性、空节点、重复根名等均易导致数据丢失或类型错误。

DataSet.ReadXml 会自动创建 DataTable 吗?
不会自动创建你想要的 DataTable 结构——它只按 XML 的根节点和嵌套层级推断表名与关系,且默认把所有子元素当列。如果你的 XML 是扁平结构(比如只有 <row></row> 包裹字段),DataSet.ReadXml 通常能凑合用;但只要 XML 有命名空间、属性混用、重复根名或空节点,DataTable 列类型就大概率是 string,且容易丢数据。
- XML 中用
attribute存数值(如<item id="123"></item>)→ 默认不转成列,除非显式设置ReadXmlSchema或手动处理 - XML 里同一层多个同名节点(如多个
<record></record>)→ 能读,但若中间夹了注释或文本节点,ReadXml可能直接抛InvalidOperationException - 没提供 XSD 或内联 schema → 所有列类型 fallback 为
string,后续做数值计算得自己Convert.ToInt32,很被动
DataTable.Load 不能直接读 XML,得先转成 XmlReader
DataTable.Load 只接受 IDataReader,不认 XML 字符串或文件路径。硬要走这条路,必须绕一下:用 XmlReader.Create 包一层,再喂给 DataSet.ReadXml —— 但注意,DataSet.ReadXml 才是真正干活的,DataTable.Load 在这里根本用不上。
- 错误写法:
table.Load("data.xml")→ 编译不过,Load方法不接受string - 正确路径:
dataset.ReadXml(XmlReader.Create("data.xml")),然后从dataset.Tables[0]拿表 - 如果 XML 很大,用
XmlReader可避免一次性加载整个字符串进内存,比File.ReadAllText+ReadXml(string)更稳
空值、命名空间、嵌套层级导致 DataTable 列缺失或错乱
XML 里一个 <price></price>(自闭合)和 <price></price>(空元素),在 .NET 的 XML 解析器眼里是两种东西,默认都映射成空字符串,但 DataTable 不会自动设 AllowDBNull = true,后续插入 null 会炸。
- XML 带命名空间(如
xmlns="http://example.com")→ReadXml会静默失败,表里没数据也不报错,得提前用XmlNamespaceManager或删掉 namespace - 嵌套两层以上(如
<orders><order><items><item>…</item></items></order></orders>)→DataSet可能建出Orders、Order、Items、Item四个表,并加外键关系,而不是你想要的单表Item - 解决办法:用
XmlDocument先选中目标节点列表,逐个提取字段,手动生成DataRow,控制列名、类型、nullability
更可控的做法:用 LINQ to XML + 手动填充 DataTable
当 XML 结构固定、字段不多时,XDocument.Load + Select + DataTable.Rows.Add 反而更直白,类型、空值、字段顺序全由你定,不依赖 XML 自动推断。
var doc = XDocument.Load("data.xml");
var table = new DataTable();
table.Columns.Add("Id", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Active", typeof(bool));
foreach (var el in doc.Root.Elements("Item"))
{
table.Rows.Add(
(int)el.Element("Id"),
(string)el.Element("Name"),
(bool?)el.Element("Active") ?? false
);
}
- 好处:字段名拼错会编译报错;类型转换失败在运行时报,位置明确;空元素可统一用
??处理 - 代价:XML 结构一变,代码就得改;没法自动适配未知字段
- 别省略
typeof(int)这类列类型声明——否则DataTable默认全object,后期绑定很麻烦










