I have the following method GetData that creates a StreamReader from a file.
private void GetData(string file)
{
string filename = Path.GetFileNameWithoutExtension(file);
XmlDocument xmldoc = new XmlDocument();
using (StreamReader sr = new StreamReader(file))
{
Stream bs = sr.BaseStream;
Stream cl = mainParser.CleanMarkup(bs);
try
{
xmldoc = mainParser.LoadDocument(bs);
}
catch (XmlException ex)
{
// Exceptions are usually caused by non-compliant documents.
// These errors are not critical to the operation of this program.
Console.WriteLine(filename + " " + ex.Message);
}
}
Msdn msdnParser = new Msdn(xmldoc);
ListViewItem lvitem = new ListViewItem(filename);
lvitem.SubItems.Add(filename);
foreach (string item in msdnParser.Subitems)
{
lvitem.SubItems.Add(item);
}
listView.Items.Add(lvitem);
}
mainParser.LoadDocument(bs) calls the following:
public XmlDocument LoadDocument(Stream file)
{
XmlDocument xmldoc = new XmlDocument();
XmlReader xmlread = XmlReader.Create(file);
xmldoc.Load(xmlread);
return xmldoc;
}
StreamReader is disposed by GetData. Does this mean that I don't have to dispose of XmlReader since (I believe) this would dispose of its only unmanaged resource?
The best "rule of thumb" to work by is:
If something implements IDisposable, always wrap it in a using() block to ensure that any unmanaged resources it owns are disposed of correctly.
Relying on the fact that the current implementation of "something" disposes of an underlying resource is dangerous and it won't hurt to wrap everything in a using, just to be on the safe side =)
You're right, you don't have to dispose the reader. But in the code given, it wouldn't hurt either.
I would not put a using block inside LoadDocument() because it is designed so that it 'borrows' it's stream (it does not create it).
But there are arguments to Dispose the XmlReader anyway, just because it's IDisposable. I don't think there is a clear winner here because of the disputable design of the Reader (and Writer) family: They Dispose their baseStreams without clearly being the owner of those streams.
Related
XmlDocument is adding a space at the end of self closing tags, even with PreserveWhitespace set to true.
// This fails
string originalXml = "<sample><node id=\"99\"/></sample>";
// Convert to XML
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.LoadXml(originalXml);
// Save back to a string
string extractedXml = null;
using (MemoryStream stream = new MemoryStream())
{
doc.Save(stream);
stream.Position = 0;
using(StreamReader reader = new StreamReader(stream))
{
extractedXml = reader.ReadToEnd();
}
}
// Confirm that they are identical
Assert.AreEqual(originalXml, extractedXml);
The desired output is:
<sample><node id="99"/></sample>
But I am getting:
<sample><node id="99" /></sample>
Is there a way to suppress that extra space?
Here's how XmlDocument.Save(Stream) looks like :
public virtual void Save(Stream outStream)
{
XmlDOMTextWriter xmlDomTextWriter = new XmlDOMTextWriter(outStream, this.TextEncoding);
if (!this.preserveWhitespace)
xmlDomTextWriter.Formatting = Formatting.Indented;
this.WriteTo((XmlWriter) xmlDomTextWriter);
xmlDomTextWriter.Flush();
}
So setting PreserveWhiteSpace has no effect on the inside of the nodes. The documentation of the XmlTextWriter says :
When writing an empty element, an additional space is added between tag name and the closing tag, for example . This provides compatibility with older browsers.
So I guess there is no easy way out. Here's a workaround tho:
So I wrote a wrapper class MtxXmlWriter that is derived from XmlWriter and wraps the original XmlWriter returned by XmlWriter.Create() and does all the necessary tricks.
Instead of using XmlWriter.Create() you just call one of the MtxXmlWriter.Create() methods, that's all. All other methods are directly handed over to the encapsulated original XmlWriter except for WriteEndElement(). After calling WriteEndElement() of the encapsulated XmlWriter, " />" is replaced with "/>" in the buffer:
I am trying to dispose the memory from an XmlDocument object
using (XmlNodeReader xnrAwards = new XmlNodeReader(ndListItems))
{
ndListItems.InnerXml = ndListItems.InnerXml.Replace("_x002e_", "_").Replace("ows_", "");
dsAward.ReadXml(xnrAwards, XmlReadMode.ReadSchema);
XmlDocument xdocAwards = new XmlDocument();
xdocAwards.LoadXml(ndListItems.OuterXml);
xdocAwards.Save(ABCListName + "_XML.xml");
}
Any idea on how to dispose the memory off this object as this is giving me an outofmemoryexception
Stop using XmlDocument if memory is a concern. It loads the entire document at once, which is causing you your issues.
Use instead a stream-based reader: XmlReader
This object chunks up the file into a buffer instead of loading the entire thing.
using (XmlReader reader = XmlReader.Create(file)) {
while (reader.Read()) {
//Do processing on each
}
}
Note this is a forward-only reader, and it's not as straight-forward to use as XmlDocument, but buffering your data will ensure you don't run into further memory exceptions.
If you're curious about the mechanism used for buffering, it's a yield return behind the scenes (which is actually compiled to a switch case if you want to get down to the nitty-gritty). Here is a blog post of someone doing something similar with a text file: http://jamesmccaffrey.wordpress.com/2011/02/04/processing-a-text-file-with-the-c-yield-return-pattern/
ref: http://msdn.microsoft.com/en-us/library/vstudio/system.xml.xmlreader
I have a really strange problem with XMLReader/XMLTextReader classes.
I have a simple file load:
public void First()
{
XmlTextReader reader = new XmlTextReader(#"C:\MyXMLFile.xml");
XmlReader readerToSerialize;
XmlReader readerToLoad;
DuplicateReaders(reader, out readerToSerialize, out readerToLoad);
XmlSerializer serializer = new XmlSerializer(typeof(XMLTree));
XmlFeed = (XMLDescriptor)serializer.Deserialize(readerToSerialize);
xmlDoc.Load(readerToLoad);
}
protected void DuplicateReaders(XmlTextReader xmlReader, out XmlReader cloneOne, out readerToLoad)
{
XmlDocument _XmlDocument = new XmlDocument();
MemoryStream _Stream = new MemoryStream();
_XmlDocument.Load((XmlTextReader)xmlReader);
_XmlDocument.Save(_Stream);
_Stream.Position = 0L;
cloneOne = XmlReader.Create(_Stream);
_Stream.Position = 0L;
cloneTwo = XmlReader.Create(_Stream);
}
The problem is that only one of the cloned elements read the whole file successully, the next one (xmlDoc.Load) fails always at the same place (Line 91, Character 37 with this xml file). If I directly assign to xmlDoc (i.e. clone the original element only once and asign it directly from the function):
public void First()
{
XmlTextReader reader = new XmlTextReader(#"C:\MyXMLFile.xml");
XmlReader readerToSerialize;
DuplicateReaders(reader, out readerToSerialize);
XmlSerializer serializer = new XmlSerializer(typeof(XMLTree));
XmlFeed = (XMLDescriptor)serializer.Deserialize(readerToSerialize);
}
protected void DuplicateReaders(XmlTextReader xmlReader, out XmlReader cloneOne)
{
XmlDocument _XmlDocument = new XmlDocument();
MemoryStream _Stream = new MemoryStream();
_XmlDocument.Load((XmlTextReader)xmlReader);
_XmlDocument.Save(_Stream);
_Stream.Position = 0L;
cloneOne = XmlReader.Create(_Stream);
_Stream.Position = 0L;
this.xmlDoc.Load(_Stream);
}
I still get the same error 91/37 (Unexpected EOF), but this time in the Serializer.
My initial problem was that if I use xmlDoc.Load(reader) the reader instance get destroyed and I can't serialize it later on. I found the Duplicate function on the MSDN forums, but it's still a no go. What I want to achieve is quite simple:
Use only one reader and get one XmlDocument and one Serialized Class. How hard can it be?
You need to close the first reader before you can use the duplicate.
reader.Close()
Your both cloneOne and cloneTwo use the same underlying memory stream.
use a different MemoryStream
cloneTwo = XmlReader.Create(new MemoryStream(_Stream.ToArray()));
Found much easier solution, instead of cloning the two readers, i just use create a second one from XmlDoc and use it to deserialize.
how do I close this document that was called this way:
var xmlDoc = XDocument.Load(new XmlTextReader(Server.MapPath("Nc.xml")));
thanks
XmlTextReader implements IDisposable. In general, you should call IDisposable.Dispose() as soon as you no longer need the resource to allow the system to close open handles, etc.
The best use pattern for IDisposable is to use the using syntax, which will call IDisposable.Dispose() automatically in an implicit try..finally wrapper:
using (var reader = new XmlTextReader(Server.MapPath("Nc.xml")))
{
var xdoc = XDocument.Load(reader);
{ .. do xdoc work here .. }
} // reader disposed here
or if you want to keep the xdoc around a long time for other work but want to close the file as soon as possible, do it this way:
XDocument xdoc = null;
using (var reader = new XmlTextReader(Server.MapPath("Nc.xml")))
{
xdoc = XDocument.Load(reader);
} // reader disposed here
{ .. do xdoc work here .. }
Once the reader is done, it will close the what it has read automatically.
otherwise hang the reference out for GC by
xmlDoc = null;
which will tear down any internal open items.
Do I really need to dispose the writer below?
DataContractSerializer _serialier...
var actual = new XmlDocument();
using (var writer = actual.CreateNavigator().AppendChild())
_serialier.WriteObject(writer, myObj);
If not then the code is simplified to:
DataContractSerializer _serialier...
var actual = new XmlDocument();
_serialier.WriteObject(actual.CreateNavigator().AppendChild(), myObj);
If the object implements IDisposable, then you should call Dispose on it when you're done.
If you don't do that, then your code is dependent on the assumption that you don't need to do it. What happens when your code is later refactored such that the XmlWriter being used is one that holds on to some resource?