Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get a Stream from an XmlReader

Tags:

c#

.net

As a result of a stored procedure I get a SqlXml object, from which I can call CreateReader to get a standard XmlReader so as I can handle it in my dll.

In the business layer of the application, I have an XMySerializer that could read the xml and instantiate the business object.

However the XMySerializer.Deserialize function takes a System.IO.Stream as an input.

So, the question is how could I get a System.IO.Stream from a System.Xml.XmlReader ?

Counterwise would be easier...

like image 268
Stephane Rolland Avatar asked Jul 05 '11 14:07

Stephane Rolland


3 Answers

Actually, you can.
It just requires some libraries that not everyone uses, because they're part of BizTalk.
If you have access to the BizTalk runtime, you can utilize an XmlTranslatorStream to provide a Stream instance from an XmlReader instance:

var xmlStream = new XmlTranslatorStream(xmlReader);

There are 3 constructors you can use.

Yeah, extremely hefty requirements to get a Stream from an XmlReader, so you can see why most answers equate to "you can't get there from here!"

Hope that helps,
Jay

like image 76
Task Avatar answered Oct 31 '22 14:10

Task


The XmlReader may or may not be backed by a Stream. I've fooled around with some methods using reflection to try to get the Stream or TextWriter backing the XmlReader, but in the end I think it's probably most straightforward to write the object to a new stream; I'd recommend this method over the accepted answer because the accepted answer won't perform very well on large documents, and this is basically a simplified version of what the BizTalk version in Jay's answer will do (BizTalk does some automatic detection of whether it should use a FileStream or MemoryStream and has some other special handling for the XML):

public static class XmlExtensions
{
    public static MemoryStream ToStream(this XmlReader reader)
    {
        MemoryStream ms = new MemoryStream();
        reader.CopyTo(ms);
        return ms;
    }

    public static FileStream ToStream(this XmlReader reader, string fileName)
    {
        FileStream fs = new FileStream(fileName, FileMode.Create);
        reader.CopyTo(fs);
        return fs;
    }

    public static void CopyTo(this XmlReader reader, Stream s)
    {
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.CheckCharacters = false; // don't get hung up on technically invalid XML characters
        settings.CloseOutput = false; // leave the stream open
        using (XmlWriter writer = XmlWriter.Create(s, settings))
        {
            writer.WriteNode(reader, true);
        }
    }
}

CopyTo would allow you to set your stream up however you like; ToStream gives you a couple helpful common cases where you just want to quickly get a regular MemoryStream (for smaller XML files) or use a FileStream (for larger ones).

Of course, in the end, if you're really doing this for serialization purposes, it'd be good to just add an overload to your serialization class like:

XMySerializer.Deserialize(XmlReader reader, object graph)

Both XmlSerializer and DataContractSerializer in the BCL follow that idea...

like image 20
Dan Field Avatar answered Oct 31 '22 14:10

Dan Field


I think there is no way, getting the stream, the XmlReader uses. The Workaround would be to use XmlReader.ReadOuterXml() to get the whole XML as a string and put it in a MemoryStream.

like image 3
Hinek Avatar answered Oct 31 '22 16:10

Hinek