2011-06-23 3 views
0

TCPを介してXMLを私にストリームするサードパーティ製のシステムがあるとします。 TOTAL送信XMLコンテンツ(ない1つのストリームのメッセージが、連結されたメッセージ)は、次のようになります。.NET3.5で不正な形式のXMLを処理しています

<root> 
     <insert ....><remark>...</remark></insert> 
     <delete ....><remark>...</remark></delete> 
     <insert ....><remark>...</remark></insert> 
     .... 
     <insert ....><remark>...</remark></insert> 
    </root> 

上記のサンプルの各行が個別に処理可能です。それはストリーミングプロセスなので、すべてが到着するまで待つだけのことはできません。私はコンテンツを処理する必要があります。問題は、任意の点でコンテンツチャンクをスライスすることができ、タグが尊重されないことです。 コンテンツがこのような断片で到着した場合、コンテンツの処理方法に関する良いアドバイスはありますか?

チャンク1:

<root> 
     <insert ....><rem 

チャンク2:

     ark>...</remark></insert> 
     <delete ....><remark>...</remark></delete> 
     <insert ....><remark>...</rema 

チャンクN:

        rk></insert> 
     .... 
     <insert ....><remark>...</remark></insert> 
    </root> 

EDIT:

処理速度は問題ではありません(リアルタイムのトラブルはありません)。メッセージ全体を待つことはできません。実際には最後のチャンクは到着しません。サードパーティシステムは、変更が発生するたびにメッセージを送信します。プロセスは決して終わらず、決して停止しないストリームです。

+0

リアルタイムで処理する必要がありますか、完全なコンテンツを取得するまで待つことはできますか?言い換えれば、XMLフラグメントを処理したり、ストリームからのデータを最もエレガントで効率的な方法で結合することに関するこの問題はありますか? – daveaglick

+1

私はあなたが 'XmlReader'クラスを使用することができますブロッキングの読み取りを使用できると思う。ノンブロッキングIOでどのように処理するかは考えられません。 – CodesInChaos

+1

あなたは、チャンクを受け取ったときに処理可能な部分を取り出し、処理することができます(できるだけあれば、非同期は良いでしょう)し、次にチャンクを追加するような文字列操作を使用する必要があるように聞こえます左、そしてそのようなループラウンド。 –

答えて

0

さらに調査した結果、XMLストリームは完全な状態になったときにTCPバッファによってスライスされていることが分かりました。したがって、スライスは実際にはバイトストリーム内でランダムに発生し、ユニコード文字内でさえもカットを引き起こしました。 したがって、パートをバイトレベルでアセンブルし、それをテキストに変換する必要がありました。変換が失敗した場合は、次のバイトチャンクを待ってから再試行します。

2

この問題の最初の考えは、ストリームからの入力をバッファリングする単純なTextReader派生物を作成することです。このクラスは、XmlReaderにフィードするために使用されます。 TextReaderの派生物は、XMLの完全な "ブロック"(始まりと終わりの括弧、テキスト断片、完全な属性などを含む完全な要素)を探して入ってくるコンテンツをかなり簡単にスキャンできます。 1つまたは複数の「ブロック」が利用可能であることを示すために、呼び出しコードにフラグを提供して、XmlReaderから次のXMLノードを尋ねることができます。これにより、TextReader派生からブロックを送信し、バッファから削除します。

編集:ここではすばやく汚れた例があります。私はそれが完全に動作するかどうかはわかりませんが(私はそれをテストしていませんが)、私が伝えようとしていたアイデアを捉えています。

public class StreamingXmlTextReader : TextReader 
{ 
    private readonly Queue<string> _blocks = new Queue<string>(); 
    private string _buffer = String.Empty; 
    private string _currentBlock = null; 
    private int _currentPosition = 0; 

    //Returns if there are blocks available and the XmlReader can go to the next XML node 
    public bool AddFromStream(string content) 
    { 
     //Here is where we would can for simple blocks of XML 
     //This simple chunking algorithm just uses a closing angle bracket 
     //Not sure if/how well this will work in practice, but you get the idea 
     _buffer = _buffer + content; 
     int start = 0; 
     int end = _buffer.IndexOf('>'); 
     while(end != -1) 
     { 
      _blocks.Enqueue(_buffer.Substring(start, end - start)); 
      start = end + 1; 
      end = _buffer.IndexOf('>', start); 
     } 

     //Store the leftover if there is any 
     _buffer = end < _buffer.Length 
      ? _buffer.Substring(start, _buffer.Length - start) : String.Empty; 

     return BlocksAvailable; 
    } 

    //Lets the caller know if any blocks are currently available, signaling the XmlReader can ask for another node 
    public bool BlocksAvailable { get { return _blocks.Count > 0; } } 

    public override int Read() 
    { 
     if (_currentBlock != null && _currentPosition < _currentBlock.Length - 1) 
     { 
      //Get the next character in this block 
      return _currentBlock[_currentPosition++]; 
     } 
     if(BlocksAvailable) 
     { 
      _currentBlock = _blocks.Dequeue(); 
      _currentPosition = 0; 
      return _currentBlock[0]; 
     } 
     return -1; 
    } 
} 
関連する問題