XML节点属性替换程序IO异常解决及混合格式节点过滤问询
解决XML中混合格式disp-formula节点的过滤与IOException问题
第一步:精准识别并过滤混合格式节点
首先要明确我们需要处理的节点规则:仅保留disp-formula节点中id为deqnX-Y格式,且X和Y格式一致的节点(要么都是纯数字,要么都是包含数字+字母的36进制字符串),像deqn5-7c(X纯数字、Y混合)或deqn2a-4(X混合、Y纯数字)这类格式不一致的节点直接跳过。
实现过滤的核心代码
先写两个辅助判断方法,再结合正则匹配完成过滤:
// 判断字符串是否为纯数字 private static bool IsPureNumber(string s) { return long.TryParse(s, out _); } // 匹配deqnX-Y格式的正则(忽略大小写) private static readonly Regex ValidRangePattern = new Regex(@"^deqn([0-9a-z]+)-([0-9a-z]+)$", RegexOptions.IgnoreCase); // 遍历disp-formula节点时的过滤逻辑 foreach (XmlNode formulaNode in xmlDoc.SelectNodes("//disp-formula[@id]")) { string id = formulaNode.Attributes["id"].Value; var match = ValidRangePattern.Match(id); if (!match.Success) continue; string x = match.Groups[1].Value; string y = match.Groups[2].Value; // 判断X和Y格式是否一致:要么都是纯数字,要么都不是纯数字 bool xIsPureNum = IsPureNumber(x); bool yIsPureNum = IsPureNumber(y); if ((xIsPureNum && !yIsPureNum) || (!xIsPureNum && yIsPureNum)) { continue; // 跳过混合格式节点 } // 后续的映射字典创建、节点替换逻辑... }
第二步:解决System.IO.IOException异常
这个异常大概率是文件读写冲突导致的(比如程序同时读写同一个文件,或文件被其他进程占用),可以通过以下两种方式解决:
方式1:内存加载后一次性写入
先把整个XML文件读入内存的XmlDocument对象,处理完成后再一次性写入文件,避免长时间占用文件:
string filePath = "your-target.xml"; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(filePath); // 执行所有节点处理逻辑(包括过滤混合格式)... // 处理完成后覆盖原文件 xmlDoc.Save(filePath);
方式2:使用临时文件中转
如果担心覆盖原文件出错,或者文件被占用,可以先写入临时文件,处理完成后替换原文件:
string tempPath = Path.GetTempFileName(); xmlDoc.Save(tempPath); // 替换原文件 File.Delete(filePath); File.Move(tempPath, filePath);
第三步:优化大文件处理效率
如果你的XML文件体积较大,建议使用流式处理+哈希字典提升效率:
- 用
XmlReader流式读取节点,避免加载整个文件到内存; - 用
Dictionary<string, string>存储rid映射,保证O(1)的查找速度。
流式处理示例代码
string filePath = "your-target.xml"; string tempPath = Path.GetTempFileName(); Dictionary<string, string> ridMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); // 第一遍遍历:收集符合条件的映射关系 using (XmlReader reader = XmlReader.Create(filePath)) { while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element && reader.Name == "disp-formula") { string id = reader.GetAttribute("id"); if (id == null) continue; var match = ValidRangePattern.Match(id); if (!match.Success) continue; string x = match.Groups[1].Value; string y = match.Groups[2].Value; // 过滤混合格式 bool xIsPureNum = IsPureNumber(x); bool yIsPureNum = IsPureNumber(y); if ((xIsPureNum && !yIsPureNum) || (!xIsPureNum && yIsPureNum)) continue; // 转换36进制范围,生成所有映射键 long start = Convert.ToInt64(x, 36); long end = Convert.ToInt64(y, 36); for (long i = start; i <= end; i++) { string rid = $"deqn{Convert.ToString(i, 36)}"; if (!ridMap.ContainsKey(rid)) ridMap.Add(rid, id); } } } } // 第二遍遍历:替换xref节点的rid属性 using (XmlReader reader = XmlReader.Create(filePath)) using (XmlWriter writer = XmlWriter.Create(tempPath)) { while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element && reader.Name == "xref" && reader.GetAttribute("ref-type") == "disp-formula") { string rid = reader.GetAttribute("rid"); if (rid != null && ridMap.TryGetValue(rid, out string newRid)) { // 写入替换后的节点 writer.WriteStartElement("xref"); writer.WriteAttributeString("ref-type", "disp-formula"); writer.WriteAttributeString("rid", newRid); writer.WriteRaw(reader.ReadInnerXml()); writer.WriteEndElement(); continue; } } // 其他节点直接复制 writer.WriteNode(reader, true); } } // 替换原文件 File.Delete(filePath); File.Move(tempPath, filePath);
内容的提问来源于stack exchange,提问作者Don_B
相关产品推荐
相关产品推荐

