C# DataSet.ReadXml读取XML返回行结构异常 未生成预期列结构
问题描述
我正尝试使用DataSet的ReadXml方法从XML文件创建DataTable,但始终无法正确定义Schema以正确解析目标文件。
问题根源在于XML的嵌套结构设计:本应作为列名的ColumnUid是节点值而非元素名称。
当前方法返回的DataTable结构错误:
期望得到的目标表结构:
我想确认是否可以通过为ReadXml传入正确定义的Schema实现该需求?虽然可以在初次读取后通过LINQ或循环转置DataTable得到目标结构,但更希望避免这类后续处理。
精简后的XML示例
<?xml version="1.0" encoding="utf-16"?> <DataTable Uid="dtDocRows"> <Rows> <Row> <Cells> <Cell> <ColumnUid>DocEntry</ColumnUid> <Value>121496</Value> </Cell> <Cell> <ColumnUid>DocNum</ColumnUid> <Value>264803</Value> </Cell> <Cell> <ColumnUid>LineNum</ColumnUid> <Value>0</Value> </Cell> <Cell> <ColumnUid>ItemCode</ColumnUid> <Value>BENIGRAMST55060075L</Value> </Cell> <Cell> <ColumnUid>Quantity</ColumnUid> <Value>1.000000</Value> </Cell> </Cells> </Row> <Row> <Cells> <Cell> <ColumnUid>DocEntry</ColumnUid> <Value>121658</Value> </Cell> <Cell> <ColumnUid>DocNum</ColumnUid> <Value>264965</Value> </Cell> <Cell> <ColumnUid>LineNum</ColumnUid> <Value>0</Value> </Cell> <Cell> <ColumnUid>ItemCode</ColumnUid> <Value>PYCCHANT202575L</Value> </Cell> <Cell> <ColumnUid>Quantity</ColumnUid> <Value>1.000000</Value> </Cell> </Cells> </Row>
当前使用的C#函数代码
private DataTable getDotNetDataTable() { DataSet ds = new DataSet(); XDocument xdoc = XDocument.Parse(dtDocRows.SerializeAsXML(SAPbouiCOM.BoDataTableXmlSelect.dxs_DataOnly)); xdoc.Save(@"C:\1\xml\test.xml"); ds.ReadXml(@"C:\1\xml\test.xml"); return ds.Tables.Item(4); return dt; }
答案
ReadXml不支持这种「将节点值动态映射为列名」的结构解析,就算传入自定义XSD Schema也无法实现,因为XSD只能定义固定的元素/属性与列的映射关系,无法把动态变化的节点值转换为列名。
不需要读取后再做整表转置,直接在读取前用LINQ to XML把源XML转换成ReadXml能识别的标准结构即可,转换逻辑非常轻量:
private DataTable getDotNetDataTable() { // 直接加载序列化得到的XML,无需存本地文件 XDocument xdoc = XDocument.Parse(dtDocRows.SerializeAsXML(SAPbouiCOM.BoDataTableXmlSelect.dxs_DataOnly)); // 结构转换:将每个Row下的Cell节点转为「ColumnUid值为元素名、Value值为元素值」的标准节点 var transformedRows = xdoc.Descendants("Row") .Select(row => new XElement("Row", row.Descendants("Cell") .Select(cell => new XElement( cell.Element("ColumnUid")?.Value, cell.Element("Value")?.Value )) ) ); // 构造ReadXml可直接识别的标准XML结构 XDocument standardFormatXml = new XDocument( new XElement("DataSetRoot", transformedRows) ); DataTable targetTable = new DataTable(); // 直接读取转换后的XML流,自动生成匹配预期的列结构和行数据 targetTable.ReadXml(standardFormatXml.CreateReader()); return targetTable; }
转换后的XML每个<Row>节点下直接挂载<DocEntry>121496</DocEntry>、<DocNum>264803</DocNum>这类节点,ReadXml会自动将节点名识别为列名、节点值识别为对应行的字段值,读取出的表结构完全符合预期,不需要后续额外处理。
该方案自动兼容不同行存在不同字段的场景,ReadXml会自动把所有出现过的ColumnUid建成列,对应行缺失该字段时值为DBNull。
内容的提问来源于stack exchange,提问作者Praxiom
相关产品推荐
相关产品推荐

