I'm trying to process a MemoryStream of XML data, which at any point in
time may have incomplete fragments (because data arrives from a
socket).
If I process data until XmlTextReader.Read() returns false, fills it
with more data, and reverses the position of the underlying
MemoryStream, the XmlTextReader immediately stops working. I apparently
have to re-create the XmlTextReader instance when I make changes to the
MemoryStream.
The XmlTextReader constructor apparently advances the position of the
MemoryStream to the end even before I've tried to Read(), which makes
it hard to know exactly where in the underlying stream Read() attempts
fail.
So the bottom line is, I want to be able to successively append
incoming data from a socket and parse it as XML, without missing
anything. Is there a way to do it? I've looked like crazy on the web
and in relevant newsgroups without finding a solution.
I'm posting sample code which demonstrates my problems. I'd really
appreciate any ideas at all on how to make it work!
The output from my sample code is:
--- First test, which works ---
Read data: SomeElement
Read data: SomeElement
--- Second test, throws an exception ---
Read data: SomeElement
Read data: NestedElement
XmlException!
--- Third test, fails ---
XmlException!
Read data:
My sample code (sorry for the somewhat poor formatting):
// XmlProblem.cs
using System;
using System.IO;
using System.Xml;
using System.Text;
using System.Diagnostics;
namespace XmlTest
{
class Test
{
void Run()
{
XmlProcessor r;
Debug.WriteLine("--- First test, which works ---");
// In this test my data consists of a legal start and end
element.
r = new XmlProcessor();
r.Insert("<SomeElement></SomeElement>");
r.Parse();
Debug.WriteLine("--- Second test, throws an exception ---");
// In this test I have a nested element and neither has
// corresponding end elements, because these haven't yet been
// read from our imaginary (in this sample) socket. This
// works ok but I'd really like to get rid of the exception,
// because MSDN states that the state of an XmlTextReader
// after an XmlException is unreliable so I'd have to throw
// it away and reinitialize it anyway, making it difficult to
// add more data.
r = new XmlProcessor();
r.Insert("<SomeElement><NestedElement>");
r.Parse();
Debug.WriteLine("--- Third test, fails ---");
// In this test our imaginary socket retrieves fragments of
// the element in pieces of two. Unfortunately even the first
// attempt to read throws an exception and the second read
// returns incomplete data.
r = new XmlProcessor();
r.Insert("<Some");
r.Parse();
r.Insert("Element>");
r.Parse();
Debug.Flush();
}
[STAThread]
static void Main(string[] args)
{
Test t = new Test();
t.Run();
}
}
public class XmlProcessor
{
private MemoryStream m_Stream = new MemoryStream();
private XmlTextReader m_Reader = null;
public XmlProcessor()
{
}
public void Insert(string data)
{
byte[] buffer = Encoding.ASCII.GetBytes(data.ToString());
long beforePos = m_Stream.Position;
m_Stream.Write(buffer, 0, buffer.Length);
m_Stream.Position = beforePos;
m_Reader = new XmlTextReader(m_Stream, XmlNodeType.Element,
null);
}
public bool Parse()
{
try
{
while (m_Reader.Read())
{
Debug.WriteLine("Read data: " + m_Reader.Name);
}
}
catch (XmlException)
{
Debug.WriteLine("XmlException!");
}
return false;
}
}
}