tags:

views:

193

answers:

2

I have a method which returns some xml in a memory stream

private MemoryStream GetXml()
{
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Indent = true;

    using (MemoryStream memoryStream = new MemoryStream())
    {
        using (XmlWriter writer = XmlWriter.Create(memoryStream, settings))
        {
            writer.WriteStartDocument();
            writer.WriteStartElement("root");
            writer.WriteStartElement("element");
            writer.WriteString("content");
            writer.WriteEndElement();
            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Flush();
        }

        return memoryStream;
    }
}

In this example the format of the xml will be:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <element>content</element>
</root>

How can i insert a new element under the root e.g

<?xml version="1.0" encoding="utf-8"?>
<root>
  <element>content</element>
  ----->New element here <------
</root>

EDIT:

Also please suggest the most efficient method as returning a memorystream may not be the best solution.

The final xml will be passed to a custom HttpHandler so what are the best options for writing the output?

context.Response.Write vs context.Response.OutputStream

+2  A: 

Your first issue is that you don't have XML - you have a stream of bytes which can be loaded into an XDocument or XmlDocument. Do you really need to output to a stream instead of directly into an XML Document?

BTW, I think you need to lose the using block around the MemoryStream. You won't be able to use the stream for much after it's been disposed.

public void AppendElement()
{
    XDocument doc;
    using(MemoryStream stream = GetXml())
    {
        using(var sr = new StreamReader(stream))
        {
            doc = XDocument.Load(sr);
        }
    }
    if(doc.Root != null)
    {
        doc.Root.Add(new XElement("Whatever"));
    }
}

private static MemoryStream GetXml()
{
    var settings = new XmlWriterSettings {Indent = true};

    var memoryStream = new MemoryStream();
    using (XmlWriter writer = XmlWriter.Create(memoryStream, settings))
    {
        writer.WriteStartDocument();
        writer.WriteStartElement("root");
        writer.WriteStartElement("element");
        writer.WriteString("content");
        writer.WriteEndElement();
        writer.WriteEndElement();
        writer.WriteEndDocument();
        writer.Flush();
    }

    return memoryStream;
}

For efficiency, try to work directly with XDocument. You seem to want to use XmlWriter, so here's how to do it (not tested):

public void AppendElement()
{
    XDocument doc = GetXml();
    if(doc.Root != null)
    {
        doc.Root.Add(new XElement("Whatever"));
    }
}

private static XDocument GetXml()
{
    var doc = new XDocument();

    using (XmlWriter writer = doc.CreateWriter())
    {
        writer.WriteStartDocument();
        writer.WriteStartElement("root");
        writer.WriteStartElement("element");
        writer.WriteString("content");
        writer.WriteEndElement();
        writer.WriteEndElement();
        writer.WriteEndDocument();
        writer.Flush();
    }

    return doc;
}

Update:

You can write the XML with

doc.Save(HttpContext.Response.Output);

Again, I can't test it now, but try this:

private static XDocument GetXml()
{
    return new XDocument(
        new XElement(
            "root", 
            new XElement(
                "element", 
                "content")));
}
John Saunders
Indeed i could return an XDocument if that makes it easiest to inject additional elements. Not really sure what is best to keep the overheads low. Hence my initial reason to return a stream.
Your last edit (static XDocument GetXml()) is actually like something I just wrote and tested, so yes, it does work. Good work.
Anthony Pegram
A: 

Consider something like this

XElement element = XElement.Parse(@" <root> 
                                      <element>content</element> 
                                    </root>");

element.Element("element").AddAfterSelf(new XElement("foo", "blah"));
Anthony Pegram