Reputation: 1414
I have been using this handy function to "beautify" an xml document, so that it's formatted with indentations and newlines. But with bigger documents (~1MB), I get an OutOfMemoryException at doc.Save(writer) for some reason. How can I fix this issue?
public static string BeautifyXmlDocument(XmlDocument doc)
{
MemoryStream sb = new MemoryStream();
XmlWriterSettings s = new XmlWriterSettings();
s.Indent = true;
s.IndentChars = " ";
s.NewLineChars = "\r\n";
s.NewLineHandling = NewLineHandling.Replace;
s.Encoding = new UTF8Encoding(false);
XmlWriter writer = XmlWriter.Create(sb, s);
doc.Save(writer);
writer.Close();
return Encoding.UTF8.GetString(sb.ToArray());
}
Stack trace:
at System.IO.MemoryStream.set_Capacity(Int32 value)
at System.IO.MemoryStream.EnsureCapacity(Int32 value)
at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count)
at System.Xml.XmlUtf8RawTextWriter.FlushBuffer()
at System.Xml.XmlUtf8RawTextWriter.RawText(Char* pSrcBegin, Char* pSrcEnd)
at System.Xml.XmlUtf8RawTextWriter.RawText(String s)
at System.Xml.XmlUtf8RawTextWriter.WriteFullEndElement(String prefix, String localName, String ns)
at System.Xml.XmlUtf8RawTextWriterIndent.WriteFullEndElement(String prefix, String localName, String ns)
at System.Xml.XmlWellFormedWriter.WriteFullEndElement()
at System.Xml.XmlElement.WriteTo(XmlWriter w)
at System.Xml.XmlElement.WriteContentTo(XmlWriter w)
at System.Xml.XmlElement.WriteTo(XmlWriter w)
at System.Xml.XmlElement.WriteContentTo(XmlWriter w)
at System.Xml.XmlElement.WriteTo(XmlWriter w)
at System.Xml.XmlElement.WriteContentTo(XmlWriter w)
at System.Xml.XmlElement.WriteTo(XmlWriter w)
at System.Xml.XmlElement.WriteContentTo(XmlWriter w)
at System.Xml.XmlElement.WriteTo(XmlWriter w)
at System.Xml.XmlElement.WriteContentTo(XmlWriter w)
at System.Xml.XmlElement.WriteTo(XmlWriter w)
at System.Xml.XmlDocument.Save(XmlWriter w)
Upvotes: 3
Views: 1726
Reputation: 23747
As long as your implementation requires getting a full string of the document, someone can always create an XmlDocument
that will cause an OutOfMemoryException
. To really get around this, you'll need to move to using Stream
objects (any TextWriter
for example) so that only a small portion of the document is ever really in memory at any given time. If you give more details about how you use your beautified string, I or someone else could probably come up with something that could help.
If, on the other hand, you can't change your implementation to avoid having the entire string in memory, you should change your posted implementation to use a StringWriter
and pass that to XmlWriter.Create
instead. This at least gets rid of some memory pressure since you won't have the MemoryStream
and the final string
in memory at the same time:
public static string BeautifyXmlDocument(XmlDocument doc)
{
using (StringWriter sw = new StringWriter())
{
XmlWriterSettings s = new XmlWriterSettings();
s.Indent = true;
s.IndentChars = " ";
s.NewLineChars = "\r\n";
s.NewLineHandling = NewLineHandling.Replace;
s.Encoding = new UTF8Encoding(false);
using (XmlWriter writer = XmlWriter.Create(sw, s))
{
doc.Save(writer);
}
return sw.ToString();
}
}
Upvotes: 1
Reputation: 43596
Maybe try returning your string before closing the stream, The "using" statement can help here. This seems to work fine for a 5MB xml file.
public static string BeautifyXmlDocument(XmlDocument doc)
{
using (MemoryStream sb = new MemoryStream())
{
XmlWriterSettings s = new XmlWriterSettings();
s.Indent = true;
s.IndentChars = " ";
s.NewLineChars = "\r\n";
s.NewLineHandling = NewLineHandling.Replace;
s.Encoding = new UTF8Encoding(false);
using (XmlWriter writer = XmlWriter.Create(sb, s))
{
doc.Save(writer);
return Encoding.UTF8.GetString(sb.ToArray());
}
}
}
Upvotes: 1