John_Sheares
John_Sheares

Reputation: 1414

XmlDocument.Save OutOfMemory exception

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

Answers (2)

Patrick Quirk
Patrick Quirk

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

sa_ddam213
sa_ddam213

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

Related Questions