XmlReader – 我需要编辑一个元素并生成一个新元素

我重写了一个传入XmlReader的方法,我需要找到一个特定的元素,添加一个属性,然后创建一个新的XmlReader或者用修改后的内容替换现有的XmlReader。 我正在使用C#4.0

我已经使用XElement(Linq)进行了调查,但我似乎无法操纵现有元素并添加属性和值。

我知道XmlWriter有WriteAttributeString,这将是太棒了但是我不知道它是如何组合在一起的

我希望能够做到这样的事情—这是伪代码!

public XmlReader DoSomethingWonderful(XmlReader reader) { Element element = reader.GetElement("Test"); element.SetAttribute("TestAttribute","This is a test"); reader.UpdateElement(element); return reader; } 

XmlReader / Writer是顺序访问流。 您必须在一端读入,按照您想要的方式处理流,并将其写出另一端。 优点是您不需要将整个内容读入内存并构建DOM,这是您使用任何基于XmlDocument的方法所获得的。

这个方法应该让你开始:

 private static void PostProcess(Stream inStream, Stream outStream) { var settings = new XmlWriterSettings() { Indent = true, IndentChars = " " }; using (var reader = XmlReader.Create(inStream)) using (var writer = XmlWriter.Create(outStream, settings)) { while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: writer.WriteStartElement(reader.Prefix, reader.Name, reader.NamespaceURI); writer.WriteAttributes(reader, true); // // check if this is the node you want, inject attributes here. // if (reader.IsEmptyElement) { writer.WriteEndElement(); } break; case XmlNodeType.Text: writer.WriteString(reader.Value); break; case XmlNodeType.EndElement: writer.WriteFullEndElement(); break; case XmlNodeType.XmlDeclaration: case XmlNodeType.ProcessingInstruction: writer.WriteProcessingInstruction(reader.Name, reader.Value); break; case XmlNodeType.SignificantWhitespace: writer.WriteWhitespace(reader.Value); break; } } } } 

这不像派生自己的XmlWriter那么干净,但我发现它更容易。

[编辑]

如何一次打开两个流的示例可能是这样的:

 using (FileStream readStream = new FileStream(@"c:\myFile.xml", FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write)) { using (FileStream writeStream = new FileStream(@"c:\myFile.xml", FileMode.OpenOrCreate, FileAccess.Write)) { PostProcess(readStream, writeStream); } } 

你不能轻易地使用XmlReader做到这一点 – 至少,不是没有从阅读器读取整个XML文档,使用它,然后从结果创建一个新的XmlReader 。 这虽然击败了使用XmlReader的许多方面 – 即流式传输大型文档的能力。

您可能从XmlReader派生,将大多数方法调用转发到现有读取器,但在适当的地方拦截它们以添加额外的属性等……但我怀疑代码实际上非常复杂和脆弱。

我使用以下胶带编码修复它

  public XmlReader FixUpReader(XmlReader reader) { reader.MoveToContent(); string xml = reader.ReadOuterXml(); string dslVersion = GetDSLVersion(); string Id = GetID(); string processedValue = string.Format(" 

这样做我感觉很脏但是它正在工作......

我更愿意将xml加载到XmlDocument对象中,并使用Attributes集合来修改该值并调用Save方法来更新此值。 下面的代码适合我。

  public static void WriteElementValue ( string sName, string element, string value) { try { var node = String.Format("//elements/element[@name='{0}']", sName); var doc = new XmlDocument { PreserveWhitespace = true }; doc.Load(configurationFileName); var nodeObject = doc.SelectSingleNode(node); if (nodeObject == null) throw new XmlException(String.Format("{0} path does not found any matching node", node)); var elementObject = nodeObject[element]; if (elementObject != null) { elementObject.Attributes["value"].Value = value; } doc.Save(configurationFileName); } catch (Exception ex) { throw new ExitLevelException(ex, false); } 

}

我也观察到当你使用XmlWriter或XmlSerializer时,空格没有被正确保存,这有时会很烦人

  string newvalue = "10"; string presentvalue = ""; string newstr = ""; XmlReader xmlr = XmlReader.Create(new StringReader(str)); while (xmlr.Read()) { if (xmlr.NodeType == XmlNodeType.Element) { if (xmlr.Name == "priority") { presentvalue = xmlr.ReadElementContentAsString(); newstr = str.Replace(presentvalue, newvalue); } } } 

// newstr可以写回文件…即编辑的xml