XML解析问题:如何将交易数据归属到对应父节点下
问题:XML解析时交易归属错误
我在读取、解析XML文件时遇到问题:程序通过OpenFileDialog选择XML文件并读取所有节点,目前存在的问题是,XML中有ID为145、175的两个父节点,每个父节点下各有4条交易,但程序会将全部8条交易都归属到这两个父节点下。
我的代码片段
Stream myStream = null; OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.InitialDirectory = "path_of_my_File"; openFileDialog1.Filter = "xml files (*.xml)|*.xml"; openFileDialog1.FilterIndex = 2; openFileDialog1.RestoreDirectory = true; if (openFileDialog1.ShowDialog() == DialogResult.OK) { try { if ((myStream = openFileDialog1.OpenFile()) != null) { string path = openFileDialog1.FileName; XmlReader xmlFile; xmlFile = XmlReader.Create(path, new XmlReaderSettings()); DataSet ds = new DataSet(); ds.ReadXml(xmlFile); int i = 0; DataTable dt = new DataTable(); dt.Columns.Add("ID", typeof(string)); dt.Columns.Add("Date", typeof(string)); dt.Columns.Add("Transaction", typeof(string)); dt.Columns.Add("Value1", typeof(string)); dt.Columns.Add("Value2", typeof(string)); dt.Columns.Add("Value3", typeof(string)); XmlDocument xmldoc = new XmlDocument(); xmldoc.Load(path); XmlNodeList nodeList = xmldoc.SelectNodes("/statement/retailers/retailer"); foreach (XmlNode node in nodeList) { XmlNodeList nodeList2 = xmldoc.SelectNodes("/statement/retailers/retailer/terminals/terminal/transactions"); DataRow dtrow = dt.NewRow(); dtrow["ID"] = node.Attributes["ID"].Value; dt.Rows.Add(dtrow); foreach (XmlNode node2 in nodeList2) { dtrow = dt.NewRow(); dtrow["Date"] = node2["transaction"].Attributes["date"].Value; dtrow["Transaction"] = node2["transaction"].Attributes["transaction"].Value; dtrow["Value1"] = node2["transaction"].Attributes["Value1"].Value; dtrow["Value2"] = node2["transaction"].Attributes["Value2"].Value; dtrow["Value3"] = node2["transaction"].Attributes["Value3"].Value; dt.Rows.Add(dtrow); } } dataGridView2.DataSource = dt; } } catch (Exception ex) { MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message); } }
XML结构示例
<root> <factory name ="145"> <id name = "xxx" value1 ="b" value2 ="b" value3 ="b" > </factory> <factory name ="175"> <id name = "xxxxxxxxxxxx" value1 ="c" value2 ="c" value3 ="c" > </factory> </root>
请问如何修改代码,让每个父节点只对应归属自己的4条交易?
解决方案:修正交易节点的选择范围
问题出在你获取交易节点的方式上——每次循环父节点时,你都用xmldoc.SelectNodes()从整个XML文档里查询所有交易节点,这就导致每个父节点都会绑定所有的8条交易。
你需要做的是基于当前遍历的父节点来查询它下面的交易节点,而不是从根节点重新查询。具体修改步骤如下:
- 调整交易节点的查询路径
把获取交易节点的代码从:
XmlNodeList nodeList2 = xmldoc.SelectNodes("/statement/retailers/retailer/terminals/terminal/transactions");
改成:
// 从当前父节点node出发,用相对路径查询下属交易 XmlNodeList nodeList2 = node.SelectNodes("./terminals/terminal/transactions");
这里的./表示从当前节点开始查找,这样就能只获取当前父节点下的交易了。
- 优化数据行的逻辑(可选)
你当前的代码会先添加一条只有ID的空行,再添加交易行。如果想让数据更规整,可以给每条交易都带上父节点ID,修改后的交易循环部分如下:
foreach (XmlNode node2 in nodeList2) { dtrow = dt.NewRow(); dtrow["ID"] = node.Attributes["ID"].Value; // 每条交易关联对应父节点ID dtrow["Date"] = node2["transaction"].Attributes["date"].Value; dtrow["Transaction"] = node2["transaction"].Attributes["transaction"].Value; dtrow["Value1"] = node2["transaction"].Attributes["Value1"].Value; dtrow["Value2"] = node2["transaction"].Attributes["Value2"].Value; dtrow["Value3"] = node2["transaction"].Attributes["Value3"].Value; dt.Rows.Add(dtrow); }
这样就不会出现单独的空ID行,数据展示更清晰。
- 清理冗余代码
你代码里创建了DataSet ds但完全没用到,可以把这部分代码删掉,减少不必要的资源消耗。
修改后的核心循环代码如下:
XmlDocument xmldoc = new XmlDocument(); xmldoc.Load(path); XmlNodeList nodeList = xmldoc.SelectNodes("/statement/retailers/retailer"); foreach (XmlNode node in nodeList) { // 从当前父节点获取下属交易 XmlNodeList nodeList2 = node.SelectNodes("./terminals/terminal/transactions"); foreach (XmlNode node2 in nodeList2) { DataRow dtrow = dt.NewRow(); dtrow["ID"] = node.Attributes["ID"].Value; dtrow["Date"] = node2["transaction"].Attributes["date"].Value; dtrow["Transaction"] = node2["transaction"].Attributes["transaction"].Value; dtrow["Value1"] = node2["transaction"].Attributes["Value1"].Value; dtrow["Value2"] = node2["transaction"].Attributes["Value2"].Value; dtrow["Value3"] = node2["transaction"].Attributes["Value3"].Value; dt.Rows.Add(dtrow); } } dataGridView2.DataSource = dt;
这样修改后,每个父节点只会加载自己下面的4条交易,不会再出现所有交易重复绑定的问题了。
内容的提问来源于stack exchange,提问作者DRastislav
相关产品推荐
相关产品推荐

