Почему большой XML подвешивает всё подряд
Файл на 200 МБ открывается в редакторе десять минут и занимает три гигабайта памяти. Дело не в том, что редактор плохой, — дело в том, как устроен разбор XML по умолчанию.
Дерево против потока
Есть два способа разобрать XML.
Построить дерево. Документ целиком превращается в объекты: элемент, его атрибуты, дети, ссылка на родителя. Удобно — можно ходить куда угодно. Дорого: на каждый элемент приходится накладной расход в разы больше, чем занимает сам текст. Отсюда правило большого пальца: дерево весит в 5–10 раз больше файла.
Читать потоком. Разбор идёт последовательно и сообщает о событиях: «открылся элемент», «текст», «закрылся элемент». Память тратится только на то, что вы решили сохранить. Неудобно — нельзя вернуться назад, — зато размер файла перестаёт быть проблемой.
Браузер при открытии .xml строит дерево. Excel при импорте — тоже. Отсюда и поведение на больших файлах.
Как это сделано у нас
Разбор идёт в два прохода по тексту, без построения дерева вовсе.
Первый проход только считает: какие элементы встречаются, на какой глубине, сколько раз и сколько внутри них разных дочерних элементов. Память на этом уходит на небольшой словарь путей — десятки килобайт независимо от размера файла. Результат — список кандидатов на «строку таблицы» с количествами.
Второй проход извлекает только выбранный элемент. Память тратится пропорционально итоговой таблице, а не документу: из файла на 200 МБ, где вам нужны 50 000 случаев по 15 полей, получится таблица в несколько десятков мегабайт.
Честное ограничение: всё это делается в браузере, поэтому текст документа всё же читается целиком. Свыше 512 МБ мы отказываемся открывать с внятным сообщением — вместо того, чтобы подвесить вкладку.
Что делать с файлами больше гигабайта
- Разделить по счетам или периодам на стороне системы, которая их формирует. Чаще всего это возможно и полезно само по себе.
- Конвертировать в CSV потоковым скриптом и дальше работать с ним: у CSV размер не ограничен ничем, кроме диска.
- Загрузить в базу. Если такие объёмы приходят регулярно, просмотрщик — не то решение, которое нужно.
Мелочи, на которых спотыкаются разборщики
- Символ
>внутри значения атрибута. Искать конец тега простым поиском нельзя — нужно учитывать кавычки. - CDATA. Внутри таких блоков разметки нет, и всё содержимое — текст, даже если выглядит как теги.
- Самозакрывающиеся элементы.
<USL/>— это открытие и закрытие сразу. Ошибка в обработке этого случая сдвигает всю последующую вложенность, и таблица получается неверной незаметно. - Сущности.
&и числовые ссылки видаЯнужно раскрывать, иначе в данных останется разметка.
Частые вопросы
Сколько памяти нужно на файл в 100 МБ?
При потоковом разборе — порядка размера итоговой таблицы плюс сам текст документа. При построении дерева — от 500 МБ до гигабайта.
Почему Notepad++ открывает, а браузер виснет?
Редактор показывает текст и не разбирает разметку. Браузер строит дерево и применяет к нему стили.
Можно ли посмотреть только первые тысячу записей?
Да, и это разумный способ понять структуру: выберите элемент-строку и примените фильтр.