如何在Stream流中修改XML根节点名称且不使用XmlDocument?
实现方案
完全可以实现,这里提供两种符合你要求的流式处理方案,都不需要加载完整XmlDocumentDOM对象:
方案1:简易文本替换(适合当前场景)
你当前需求只是修改固定的根节点起止标签,不需要解析XML结构,直接对Stream内容做文本替换即可,代码最简执行效率最高:
// 先把原始响应流读到字符串 using StreamReader sr = new StreamReader(stream1, Encoding.UTF8); string xmlContent = sr.ReadToEnd(); // 替换根节点,保留原属性和命名空间 string modifiedXml = xmlContent .Replace("<DataTable xmlns=\"http://tempuri.org/\">", "<DataTableCars xmlns=\"http://tempuri.org/\">") .Replace("</DataTable>", "</DataTableCars>"); // 转成新的Stream供后续使用 Stream modifiedStream = new MemoryStream(Encoding.UTF8.GetBytes(modifiedXml)); // 把流的位置重置到开头,方便后续读取 modifiedStream.Seek(0, SeekOrigin.Begin);
方案2:流式XML读写(严谨无替换风险)
如果担心XML内容里其他位置存在DataTable字符串导致误替换,可以用XmlReader+XmlWriter的组合,两者都是流式处理,不会把整个XML加载到内存,资源消耗远低于XmlDocument:
// 创建输出流 MemoryStream outputStream = new MemoryStream(); using (XmlReader reader = XmlReader.Create(stream1)) using (XmlWriter writer = XmlWriter.Create(outputStream, new XmlWriterSettings() { Indent = true, Encoding = Encoding.UTF8 })) { while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: // 匹配根节点DataTable if (reader.Name == "DataTable" && reader.Depth == 0) { writer.WriteStartElement("DataTableCars", reader.NamespaceURI); // 复制原节点的所有属性 writer.WriteAttributes(reader, true); } else { writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI); writer.WriteAttributes(reader, true); if (reader.IsEmptyElement) writer.WriteEndElement(); } break; case XmlNodeType.EndElement: if (reader.Name == "DataTable" && reader.Depth == 0) { writer.WriteEndElement(); } else { writer.WriteFullEndElement(); } break; default: writer.WriteNode(reader, true); break; } } } // 重置流位置 outputStream.Seek(0, SeekOrigin.Begin); // 后续直接使用outputStream即可
方案选择建议
- 如果你能确定返回的XML结构固定,只有根节点是
DataTable标签,直接用方案1即可,代码最少、执行最快 - 如果XML内容可能存在变化、或者内部节点有概率出现
DataTable字符串,选方案2更稳妥,不会出现误替换问题
内容的提问来源于stack exchange,提问作者Allstar
相关产品推荐
相关产品推荐

