Мой пользовательский читатель XML - двуногая черепаха. Предложения? - PullRequest
1 голос
/ 15 февраля 2010

Я написал специальный XML-ридер, потому что мне нужно что-то, что не будет читаться заранее из исходного потока. Я хотел, чтобы объект мог читать свои данные из потока, не оказывая негативного влияния на поток для родительского объекта. Таким образом, поток может быть передан по дереву объектов.

Это минимальная реализация, предназначенная только для целей проекта, который ее использует (прямо сейчас). Работает достаточно хорошо, за исключением одного метода - ReadString. Этот метод используется для чтения содержимого текущего элемента в виде строки, останавливаясь при достижении конечного элемента. Это определяется путем подсчета уровней вложенности. Между тем, он читает из потока, символ за символом, добавляя StringBuilder для полученной строки.

Для элемента коллекции это может занять много времени. Я уверен, что многое можно сделать, чтобы лучше это реализовать, так что именно здесь начинается мое непрерывное образование. Я мог бы действительно использовать некоторую помощь / руководство. Некоторые примечания о методах, которые он вызывает:

Read - возвращает следующий байт в потоке или -1.

ReadUntilChar - вызывает Read до тех пор, пока не будет достигнут указанный символ или -1, добавляя строку с помощью StringBuilder.

Без лишних слов, вот моя двуногая черепаха. Константы были заменены фактическими значениями.

public string ReadString() {
    int level = 0;
    long originalPosition = m_stream.Position;
    StringBuilder sb = new StringBuilder();
    sbyte read;
    try {
        // We are already within the element that contains the string.
        // Read until we reach an end element when the level == 0.
        // We want to leave the reader positioned at the end element.
        do {
            sb.Append(ReadUntilChar('<'));
            if((read = Read()) == '/') {
                // End element
                if(level == 0) {
                    // End element for the element in context, the string is complete.
                    // Replace the two bytes of the end element read.
                    m_stream.Seek(-2, System.IO.SeekOrigin.Current);
                    break;
                } else {
                    // End element for a child element.
                    // Add the two bytes read to the resulting string and continue.
                    sb.Append('<');
                    sb.Append('/');
                    level--;
                }
            } else {
                // Start element
                level++;
                sb.Append('<');
                sb.Append((char)read);
            }
        } while(read != -1);

        return sb.ToString().Trim();
    } catch {
        // Return to the original position that we started at.
        m_stream.Seek(originalPosition - m_stream.Position, System.IO.SeekOrigin.Current);
        throw;
    }
}

Ответы [ 4 ]

3 голосов
/ 15 февраля 2010

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

После того как вы профилировали парсер, вы должны иметь представление о том, где метод ReadString() тратит все свое время, что значительно упростит вашу оптимизацию.

Одно из предложений, которое я хотел бы сделать на уровне алгоритма, - сначала просканировать поток, а затем создать его содержимое: вместо того, чтобы потреблять каждый символ, как вы его видите, отметьте, где вы найдете <, > и </ символов. Получив эти позиции, вы можете извлекать данные из потока в блоках, а не бросать символы в StringBuilder по одному за раз. Это позволит оптимизировать значительное количество StringBuilder.Append вызовов, что может повысить вашу производительность (именно здесь профилирование может помочь).

Вы можете найти этот анализ полезным для оптимизации строковых операций, если они оказываются источником медлительности.

Но на самом деле, профиль .

1 голос
/ 25 июля 2011

Я написал специальный XML-ридер, потому что мне нужно было что-то, что не читалось заранее исходный поток. Я хотел, чтобы объект мог читать свои данные из потока без негативно влияет на поток для родительского объекта. Таким образом, поток может быть передан вниз по дереву объектов.

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

Метод ReadSubtree не предназначен для создания копии данных XML, которую вы можете работать с самостоятельно. Скорее, его можно использовать для создания границы вокруг XML элемент. Это полезно, если вам нужно передать данные другому компоненту для обработки и вы хотите ограничить объем ваших данных, к которым может иметь доступ компонент. Когда вы передаете XmlReader, возвращенный методом ReadSubtree другому приложению, приложению может получить доступ только к этому XML-элементу, а не ко всему XML-документу.

В нем говорится, что после чтения поддерева родительский считыватель перемещается в «EndElement» текущего элемента, а не остается в начале, но может ли это быть проблемой?

1 голос
/ 15 февраля 2010

Ваша реализация предполагает, что Stream доступен для поиска. Если известно, что это можно найти, почему что-нибудь ? Просто создайте XmlReader в вашей позиции; потреблять данные; угробить читателя; и искать Stream туда, откуда вы начали?

Насколько большой xml? Вы можете обнаружить, что добавление данных в DOM (XmlDocument / XDocument / ec) - это эффективный способ получить читателя, который делает то, что вам нужно, не требуя больших переделок. В случае XmlDocument, например, XmlNodeReader будет достаточно (он также обеспечит поддержку xpath, если вы хотите использовать нетривиальные запросы).

0 голосов
/ 15 февраля 2010

Почему бы не использовать существующий, например этот ?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...