鉴于第三方系统通过TCP将XML流式传输给我。 TOTAL传输的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
Chunk N:
rk></insert>
....
<insert ....><remark>...</remark></insert>
</root>
编辑:
虽然处理速度不是问题(没有实时问题),但我不能等待整个消息。实际上最后一块大块永远不会到来。第三方系统在遇到更改时发送消息。这个过程永远不会结束,它是一条永不停止的流。
答案 0 :(得分:2)
我首先想到的是这个问题是创建一个简单的TextReader派生物,负责缓冲来自流的输入。然后,该类将用于提供XmlReader。 TextReader派生可以相当容易地扫描传入的内容,寻找XML的完整“块”(带有开始和结束括号的完整元素,文本片段,完整属性等)。它还可以为调用代码提供一个标志,以指示何时一个或多个“块”可用,以便它可以从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;
}
}
答案 1 :(得分:0)
经过进一步调查后,我们发现,当TCP缓冲区已满时,它已被TCP缓冲区切片。因此,切片实际上是在字节流中随机发生的,甚至在unicode字符内也会导致切割。 因此,我们必须在字节级组装部件并将其转换回文本。如果转换失败,我们等待下一个字节块,然后再次尝试。