XmlReader - I need to edit an element and create a new one

I redefine the method in which the XmlReader is passed, I need to find a specific element, add an attribute, and then either create a new XmlReader or simply replace the existing one with the changed content. I am using C # 4.0

I explored the use of XElement (Linq), but I cannot manipulate an existing element and add an attribute and value.

I know that XmlWriter has a WriteAttributeString that would be fantastic, but again I'm not sure how it all fits together

I would like to be able to do something like --- This is pseudo code!

public XmlReader DoSomethingWonderful(XmlReader reader) { Element element = reader.GetElement("Test"); element.SetAttribute("TestAttribute","This is a test"); reader.UpdateElement(element); return reader; } 
+6
c # xml xmlreader
source share
5 answers

XmlReader / Writer are sequential access threads. You will need to read on one end, process the stream as you want, and write it on the other end. The advantage is that you do not need to read all this in memory and create the DOM, which you will get with any XmlDocument-based approach.

This method should start working:

 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; } } } } 

It's not as clean as getting your own XmlWriter, but I find it a lot easier.

[EDIT]

An example of how you could open two streams at once might be something like this:

 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); } } 
+11
source share

You cannot easily do this with XmlReader - at least not skipping the entire XML document from the reader, not using it, and then creating a new XmlReader from the result. This greatly affects the use of XmlReader , namely the ability to stream large documents.

You can potentially get from XmlReader by forwarding most of the calls to methods to an existing reader, but intercepting them when necessary to add additional attributes, etc .... but I suspect the code will be really quite complex and fragile.

+1
source share

I fixed it using the following tape encoding tape

  public XmlReader FixUpReader(XmlReader reader) { reader.MoveToContent(); string xml = reader.ReadOuterXml(); string dslVersion = GetDSLVersion(); string Id = GetID(); string processedValue = string.Format("<ExampleElement dslVersion=\"{1}\" Id=\"{2}\" ", dslVersion, Id); xml = xml.Replace("<ExampleElement ", processedValue); MemoryStream ms = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(xml)); XmlReaderSettings settings = new XmlReaderSettings(); XmlReader myReader = XmlReader.Create(ms); myReader.MoveToContent(); return myReader; } 

I feel dirty for this, but it works ...

+1
source share

I prefer to load xml into an XmlDocument object and use the Attributes collection to change the value and call the Save method to update that value. Below code works for me.

  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); } 

}

I also observed when you use XmlWriter or XmlSerializer, spaces were not saved correctly, sometimes it can be annoying

0
source share
  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 can be written back to the file ... this is edited xml

-2
source share

All Articles