2011-11-21 79 views
2

我正在將數據庫中的blob作爲字節數組加載,並將它們放入內存流中,以便我可以將它們加載到xmldocument中進行解析。如何預先安排流?

但是,有斑點有多個根節點,這會導致解析器炸燬。

我的解決方案是創建一個包含整個blob的新根節點。

我可以用streamwriter加到最後,但我無法弄清楚如何添加到開始。

如何添加到流中?


更新
我有太多的麻煩這個工作。我正在提取的「XML」不是正確的XML,而且我一直需要在XmlDocument加載之前添加越來越多的正則表達式來刪除壞XML。我最終使用HtmlAgilityPack解析了XML的有效部分,並將這些部分放在自己的xml文檔中。不是最好的解決方案,但它的工作原理。 嘆息

回答

3

既然你已經從DB byte[]陣列,前後寫更多的字節數組存儲流應該是很容易:

// bytes from db 
byte[] multipleNodes = Encoding.UTF8.GetBytes("<first>..</first><second>..</second><third>..</third>"); 

using (var ms = new MemoryStream()) 
{ 
    // write opening tag 
    byte[] newRoot = Encoding.UTF8.GetBytes("<newRoot>"); 
    ms.Write(newRoot, 0, newRoot.Length); 

    ms.Write(multipleNodes, 0, multipleNodes.Length); 

    // write opening tag 
    byte[] closeNewRoot = Encoding.UTF8.GetBytes("</newRoot>"); 
    ms.Write(closeNewRoot, 0, closeNewRoot.Length); 

    // reset cursor position before pass it to xmldoc 
    ms.Position = 0; 

    var xml = new XmlDocument(); 
    xml.Load(ms); 

    Console.WriteLine(xml.InnerXml); 
} 

但由於XmlDocument還提供LoadXml(str),感覺操縱字符串應該是更直接的解決方案:

// bytes from db 
byte[] multipleNodes = Encoding.UTF8.GetBytes("<first>..</first><second>..</second><third>..</third>"); 

string stringFromBlob = Encoding.UTF8.GetString(multipleNodes); 
string withRootNode = string.Format("<newRoot>{0}</newRoot>", stringFromBlob); 

var xml = new XmlDocument(); 
xml.LoadXml(withRootNode); 

Console.WriteLine(xml.InnerXml); 
+0

您的第一個解決方案是我想建議。你的第二個,雖然直截了當,正確,感覺效率太低,以至於我不認爲第一個是不成熟的優化... – zmbq

+0

@zmbq不知道這一點,但由於OP已經得到'byte []數組加載到內存中。我覺得把它轉換爲字符串(並與其他文本一起格式化)的額外成本應該不會太高。 – Gant

4

你不能直接。這導致了兩個選項:

  • 寫在打開的標籤到的MemoryStream加載斑點
  • 創建第二個的MemoryStream之前,寫在一個開放標籤,第一複製到第二...
+0

好的,謝謝,我會給它一個鏡頭。 –

+0

否則,您可以將blob視爲片段,並使用以下方法:http://stackoverflow.com/questions/2374426/linq-to-xml-load-xml-fragments-from-file – spender

2

這是我使用的一個:

public class CompositeStream : FileStream 
{ 
    Stream[] childStreams; 
    int currentStreamIndex = 0; 
    Stream currentStream; 
    public long totalStreamRead{get; private set;} 

    public CompositeStream(string pre, FileStream s_file, string post) 
     : base(s_file.SafeFileHandle, FileAccess.Read) 
    { 
     totalStreamRead = 0; 

     MemoryStream s_pre = new MemoryStream(); 
     MemoryStream s_post = new MemoryStream(); 

     byte[] b_pre = Encoding.UTF8.GetBytes(pre); 
     s_pre.Write(b_pre, 0, b_pre.Length); 
     s_pre.Flush(); 
     s_pre.Seek(0, SeekOrigin.Begin); 

     byte[] b_post = Encoding.UTF8.GetBytes(post); 
     s_post.Write(b_post, 0, b_post.Length); 
     s_post.Flush(); 
     s_post.Seek(0, SeekOrigin.Begin); 

     childStreams = new Stream[] { s_pre, s_file, s_post }; 

     currentStream = childStreams[currentStreamIndex++]; 
    } 

    public override int Read(byte[] buffer, int offset, int count) 
    { 
     int totalBytesRead = 0; 
     while (count > 0) 
     { 
      // Read what we can from the current stream 
      int numBytesRead = currentStream.Read(buffer, offset, count); 
      totalBytesRead += numBytesRead; 
      count -= numBytesRead; 
      offset += numBytesRead; 

      // If we haven't satisfied the read request, 
      // we have exhausted the current stream. 
      // Move on to the next stream and loop around to read more data. 
      if (count > 0) 
      { 
       // If we run out of child streams to read from... 
       if (currentStreamIndex >= childStreams.Length) 
        break; //get out 

       currentStream.Close(); 
       currentStream = childStreams[currentStreamIndex++]; 
      } 
     } 
     totalStreamRead += totalBytesRead; 
     return totalBytesRead; 
    } 
}