2012-02-21 14 views
6

C#.NET 4.0でネットワークサーバーを作成しています。私は完全なXML要素を受け取ることができるネットワークTCP/IP接続があります。彼らは定期的に到着し、すぐに処理する必要があります。各XML要素はそれ自身で完全なXML文書であるため、開始要素、いくつかのサブノード、および終了要素があります。ストリーム全体に対して単一のルート要素はありません。私は、接続を開いたときに、私は何を取得することは、このようなものです:XMLネットワークストリームから要素全体を読み取る

<status> 
    <x>123</x> 
    <y>456</y> 
</status> 

そして、いくつかの時間後には続行されますように

<status> 
    <x>234</x> 
    <y>567</y> 
</status> 
と。ステータス要素が完成するまで完全なXML文字列を読み取る方法が必要です。私は、データがどのようなフォーマットになっているのかわからないので、プレーンテキストの読み方ではしたくないです。多くの場合、他の場所で説明されているように、ストリーム全体が終了するまで待つことはできません。私はXmlReaderクラスを使用しようとしましたが、ドキュメントが奇妙で、メソッドがうまくいかず、最初の要素が失われ、2つ目の要素を送信した後に2つのルート要素があるためXmlExceptionが発生します。

+0

私は、XmlReaderがルート要素を期待していて、XML要素を連続的にストリーミングするための準備ができていないため、行く方法は不明です。通常、ソケットベースの接続を処理するときは、接続をリッスンし、データの各チャンクの開始と終了を識別します。私はあなたが望んでいないと言ったことを知っていますが、私はあなたが解析できるXMLの塊を少なくとも特定するためにプレーンテキストの読み込みメソッドを使用する必要があると思います。 –

+0

メッセージが完全なノードである場合、各メッセージの新しいリーダーをインスタンス化する必要があります。 –

答えて

7

これを試してみてください:

var settings = new XmlReaderSettings 
{ 
    ConformanceLevel = ConformanceLevel.Fragment 
}; 

using (var reader = XmlReader.Create(stream, settings)) 
{ 
    while (!reader.EOF) 
    { 
     reader.MoveToContent(); 

     var doc = XDocument.Load(reader.ReadSubtree()); 

     Console.WriteLine("X={0}, Y={1}", 
      (int)doc.Root.Element("x"), 
      (int)doc.Root.Element("y")); 

     reader.ReadEndElement(); 
    } 
} 
+0

これはすでにそれに近いです。同じストリーム内の複数のXMLルート要素を読み取ることができますが、ReadEndElement呼び出しは、次の要素が入るまで常にブロックされます。安全に削除できますか、別のイベントを待たなければなりませんか? – ygoe

+0

ReadEndElementをブロックし、ReadSubtreeを読み込まない場合は、ReadEndElement呼び出しの前にXDocumentを処理するだけで済みます。 – dtb

+0

ありがとうございます、今はうまくいきます。 – ygoe

0

それには何も組み込まれていません。 文字列ビルダーを開き、</status>タグが見つかるまで入力してから、通常のXmlDocumentを使用して解析します。

+0

P.S.私はあなたがStringメソッドを使いたくないと書いたことを知っていますが、私はそれがあなたの唯一の方法だと確信しています。 – Svarog

1

"適合レベル"を "フラグメント"に変更すると、XmlReaderと動作する可能性があります。

これはMSDNから(わずかに修正)の例である:

XmlReaderSettings settings = new XmlReaderSettings(); 
settings.ConformanceLevel = ConformanceLevel.Fragment; 
XmlReader reader = XmlReader.Create(streamOfXmlFragments, settings); 
1

あなたはより多くので新たに追加されXML要素断片のストリーミングのためのものですXElement.Loadを使用することができます.net 3.5また、ストリームから直接読み込みをサポートしています。

は、私はあなたがよくまだあなたが受信されたメッセージを仕切るように、いくつかの制御ロジックを追加する必要がありますが、あなたにもそれをやってみることだと思いSystem.Xml.Linq

を見てください。

0

DTBの溶液から、実質的に異なっていないが、linqier

static IEnumerable<XDocument> GetDocs(Stream xmlStream) 
{ 
    var xmlSettings = new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Fragment }; 
    using (var xmlReader = XmlReader.Create(xmlStream, xmlSettings)) 
    { 
     var xmlPathNav = new XPathDocument(xmlReader).CreateNavigator(); 
     foreach (var selectee in xmlPathNav.Select("/*").OfType<XPathNavigator>()) 
      yield return XDocument.Load(selectee.ReadSubtree()); 
    } 
} 

私はPowerShellで同様の問題に遭遇したが、アスカーの質問は、C#でいたので、私はそれを翻訳しようとしてきた(そしてそれことを確認し作品)。 Hereは、私が最後のちょっとしたバンプを乗り越えてくれた手がかりを見つけた場所です( "XPathDocumentの魔法は、"透過的な "ルートノードを作成し、そこからフラグメントを保持することです)。 XPathクエリはルートノードの軸を使用することができますが、フラグメントに対して適切に解決されます。 ")

私が作業しているXMLの断片は、小さくなることがあります。より大きなチャンクがある場合は、おそらくXStreamingElementを調べることをお勧めします。多量のXMLを扱う場合、複雑さは増しますが、メモリ使用量が大幅に減少します。

関連する問題