如何避免大小写不同的XML属性在DataGridView中数据重复?
解决XML数据绑定DataGridView时ID列与id列数据重复的问题
我碰到过一模一样的坑!问题根源其实很简单:.NET里的DataTable和DataSet默认是不区分大小写的,当你的XML里同时存在小写id和大写ID这两个属性时,它们会被当成同一个字段处理,自然就会出现数据重复覆盖的情况。下面针对你用的两种方法,分别给出解决方案:
方法一:手动创建DataTable的修复方案
你之前的代码思路没问题,只是没开启DataTable的大小写敏感。只要在创建DataTable时加上CaseSensitive = true,就能让它区分"id"和"ID"两个列名,再配合安全的属性读取(避免空引用),就能正常显示数据了:
DataTable dt = new DataTable(); dt.CaseSensitive = true; // 关键:打开大小写敏感开关 dt.Columns.Add("Date", typeof(DateTime)); dt.Columns.Add("Severity", typeof(string)); dt.Columns.Add("id", typeof(string)); dt.Columns.Add("ID", typeof(string)); dt.Columns.Add("Msg", typeof(string)); XDocument docLog = XDocument.Load(XML_FILEPATH); foreach (XElement log in docLog.Descendants("Log")) { DateTime date = (DateTime)log.Attribute("Date"); string severity = (string)log.Attribute("Severity"); // 用?.Value ?? string.Empty处理属性不存在的情况,防止空引用异常 string id = log.Attribute("id")?.Value ?? string.Empty; string ID = log.Attribute("ID")?.Value ?? string.Empty; string msg = log.Attribute("Msg")?.Value ?? string.Empty; dt.Rows.Add(new object[] { date, severity, id, ID, msg }); }
方法二:DataSet.ReadXml的修复方案
DataSet的自动Schema推断默认也不区分大小写,所以要么提前定义明确的XML Schema(XSD),要么手动创建区分大小写的DataTable再让DataSet读取。
方案A:用XSD Schema约束
先写一个和你的XML结构匹配的XSD文件(比如命名为LogSchema.xsd),明确区分id和ID两个属性:
<?xml version="1.0" encoding="utf-8"?> <xs:schema id="Logging" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xs:element name="Logging" msdata:IsDataSet="true" msdata:UseCurrentLocale="true"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="Log"> <xs:complexType> <xs:attribute name="Date" type="xs:date" use="required" /> <xs:attribute name="Severity" type="xs:string" use="required" /> <xs:attribute name="id" type="xs:string" use="required" /> <xs:attribute name="ID" type="xs:string" use="required" /> <xs:attribute name="Msg" type="xs:string" use="optional" /> <xs:attribute name="Pos" type="xs:string" use="optional" /> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema>
然后修改代码,先读取Schema再加载XML:
OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Filter = @"XML files (*.xml)|*.xml|All files (*.*)|*.*"; if (openFileDialog1.ShowDialog() == DialogResult.OK) { myLogfile = openFileDialog1.FileName; var dataset = new DataSet(); dataset.CaseSensitive = true; // 开启大小写敏感 // 先读取我们定义的Schema dataset.ReadXmlSchema(@"你的XSD文件路径\LogSchema.xsd"); using (StreamReader sr = new StreamReader(openFileDialog1.FileName)) { dataset.ReadXml(sr); } var bindingSource = new BindingSource { DataSource = dataset, DataMember = "Log" }; dataGridView1.DataSource = bindingSource; }
方案B:手动创建DataTable加入DataSet
如果你不想写XSD,也可以先创建一个区分大小写的DataTable,添加到DataSet后再读取XML:
OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Filter = @"XML files (*.xml)|*.xml|All files (*.*)|*.*"; if (openFileDialog1.ShowDialog() == DialogResult.OK) { myLogfile = openFileDialog1.FileName; var dataset = new DataSet(); dataset.CaseSensitive = true; // 手动创建区分大小写的Log表 DataTable logTable = new DataTable("Log"); logTable.CaseSensitive = true; logTable.Columns.Add("Date", typeof(DateTime)); logTable.Columns.Add("Severity", typeof(string)); logTable.Columns.Add("id", typeof(string)); logTable.Columns.Add("ID", typeof(string)); logTable.Columns.Add("Msg", typeof(string)); logTable.Columns.Add("Pos", typeof(string)); // 兼容XML里的Pos属性 dataset.Tables.Add(logTable); using (StreamReader sr = new StreamReader(openFileDialog1.FileName)) { // 忽略自动推断的Schema,用我们手动创建的表结构 dataset.ReadXml(sr, XmlReadMode.IgnoreSchema); } var bindingSource = new BindingSource { DataSource = dataset, DataMember = "Log" }; dataGridView1.DataSource = bindingSource; }
两种方法都能解决你的问题,核心就是让DataTable/DataSet区分大小写,不再把id和ID当成同一个字段。
内容的提问来源于stack exchange,提问作者Baron
相关产品推荐
相关产品推荐

