2011-07-05 88 views
6

由于库存过程,我收到一个SqlXml对象,我可以从中调用CreateReader来获得标准的XmlReader,以便我可以在我的dll中处理它。从XmlReader获取流

在应用程序的业务层,我有一个XMySerializer可以读取xml并实例化业务对象。

但是,XMySerializer.Deserialize函数将System.IO.Stream作为输入。

所以,问题是我怎么能得到一个System.IO.Stream a System.Xml.XmlReader? 逆向会更容易...

回答

3

我认为没有办法,获取流,XmlReader使用。解决方法是使用XmlReader.ReadOuterXml()将整个XML作为字符串并将其放在MemoryStream中。

+0

请注意,这具有解码[通常为UTF8]编码的XML(每个字符大多为单个字节)的开销,对于每个字符为两个字节的字符串(一些字符多于I认为)。所以需要考虑文本解码成本和双倍大小的内存占用空间。 – redcalx

1

你不能。 XmlReader是一个具有许多实现的抽象类(包括一些从流中读取但其他与流无关的实现)。但是,您可以将此XML阅读器中的数据写入System.IO.MemoryStream,然后将此数据流提供给您的XMySerializer.Deserialize函数。

8

其实你可以。
它只需要一些不是每个人都使用的库,因为它们是BizTalk的一部分。
如果你有机会到BizTalk运行时,你可以利用一个XmlTranslatorStream从一个XmlReader实例提供Stream实例:

var xmlStream = new XmlTranslatorStream(xmlReader); 

There are 3 constructors就可以使用。

是的,从XmlReader获取Stream的要求非常高,所以你可以看到为什么大多数答案都等于“你无法从这里得到!”

希望帮助,
周杰伦

3

XmlReader可能会或可能不会被一个Stream支持。我用一些使用反射的方法愚弄了一下,试图获得支持XmlReader的StreamTextWriter,但最终我认为将对象写入新流可能是最直接的;我推荐这种方法超过了接受的答案,因为接受的答案在大型文档中表现不佳,这基本上是Jay答案中BizTalk版本的简化版本(BizTalk会自动检测是否它应使用FileStreamMemoryStream并先后为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将使但是你喜欢你设定流了; ToStream为您提供了一些有用的常见案例,您只需要快速获取MemoryStream(适用于较小的XML文件)或使用FileStream(适用于较大的文件)。

当然,到了最后,如果你真的这样做了系列化的目的的时候,它会是不错的,只是超载添加到您的序列化类,如:

XMySerializer.Deserialize(XmlReader reader, object graph) 

两个XmlSerializerDataContractSerializer在BCL遵循这个想法...