Обработка плохо отформатированного XML в .NET3.5 - PullRequest
0 голосов
/ 23 июня 2011

Учитывая стороннюю систему, которая передает мне XML через TCP. ВСЕГО передаваемый 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>

РЕДАКТИРОВАТЬ:

Хотя скорость обработки не имеет значения (никаких проблем в реальном времени), я не могу дождаться полного сообщения. Практически последний кусок никогда не прибывает. Сторонняя система отправляет сообщения всякий раз, когда она сталкивается с изменениями. Процесс никогда не заканчивается, это поток, который никогда не останавливается.

Ответы [ 2 ]

2 голосов
/ 23 июня 2011

Моя первая мысль об этой проблеме - создать простую производную TextReader, которая отвечает за буферизацию ввода из потока. Этот класс затем будет использоваться для подачи XmlReader. Производное TextReader может довольно легко сканировать входящий контент в поисках полных «блоков» XML (полный элемент с начальными и конечными скобками, фрагмент текста, полный атрибут и т. Д.). Он также может предоставить флаг вызывающему коду, чтобы указать, когда один или несколько «блоков» доступны, поэтому он может запросить следующий узел XML из XmlReader, который будет инициировать отправку этого блока из производной 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;
    }
}
0 голосов
/ 29 августа 2011

После дальнейших исследований мы выяснили, что поток XML был разрезан буфером TCP при каждом заполнении.Таким образом, нарезка происходит фактически случайно в потоке байтов, вызывая сокращения даже внутри символов Юникода.Поэтому мы должны были собрать части на уровне байтов и преобразовать их обратно в текст.Если разговор потерпит неудачу, мы подождали следующий байт и попытались снова.

...