Как реализовать чтение и отображение данных из XML в две таблицы на форме 1С 8.3?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Работа с XML-файлами — одна из наиболее частотных задач при организации обмена данными в 1С. Типичный сценарий: пользователю необходимо загрузить файл, увидеть список документов в первой таблице, а при выборе конкретной строки — просмотреть детальные свойства этого документа во второй таблице. Рассмотрим подробно, как решить эту задачу, какие инструменты использовать и как избежать типичных ошибок новичков, связанных с производительностью и позиционированием в файле.

Постановка задачи и анализ проблем

Основная сложность, с которой сталкиваются разработчики, заключается в потере связи между строкой в таблице на форме (которая является лишь визуальным представлением данных) и конкретным узлом в XML-структуре. Если в файле встречаются документы с одинаковыми именами, обычный поиск по текстовому значению становится невозможным. Проанализируем ситуацию: для эффективной реализации нам необходимо не только прочитать файл, но и сохранить «ключ», по которому мы сможем мгновенно найти нужные данные при клике пользователя.

Важное правило: Обработку XML-файлов всегда следует выносить на сторону сервера. Объекты ЧтениеXML, ДокументDOM и ОбъектXDTO не являются сериализуемыми, то есть их нельзя передать с сервера на клиент. На клиенте мы лишь инициируем процесс и передаем адрес файла во временном хранилище.

Способ 1: Использование DOM и индексации узлов

Метод объектной модели документа (DOM) удобен тем, что позволяет загрузить весь файл в память и обращаться к любому узлу по его индексу или через XPath-запросы. Рассмотрим, как правильно связать таблицу формы и структуру XML.

Для начала создадим на форме две таблицы: ТЗ_Документы и ТЗ_Свойства. В таблицу ТЗ_Документы обязательно добавим скрытую колонку ИндексУзла (тип: Число).

Разберем процедуру загрузки первого списка документов:


&НаСервере
Процедура ЗагрузитьСписокДокументовНаСервере(АдресФайла)
    ЧтениеXML = Новый ЧтениеXML;
    // Получаем файл из временного хранилища, куда он был помещен на клиенте
    ИмяФайла = ПолучитьИмяВременногоФайла("xml");
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресФайла);
    ДвоичныеДанные.Записать(ИмяФайла);
    
    ЧтениеXML.ОткрытьФайл(ИмяФайла);
    ПостроительDOM = Новый ПостроительDOM;
    ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
    
    ТЗ_Документы.Очистить();
    
    // Перебираем корневые элементы (например, узлы "Объект")
    ВсеУзлы = ДокументDOM.ЭлементДокумента.ДочерниеУзлы;
    Для Индекс = 0 По ВсеУзлы.Количество() - 1 Цикл
        ТекущийУзел = ВсеУзлы.Получить(Индекс);
        Если ТекущийУзел.ИмяУзла = "Объект" Тогда
            НоваяСтрока = ТЗ_Документы.Добавить();
            НоваяСтрока.Наименование = ТекущийУзел.Атрибуты.ПолучитьИменованныйЭлемент("Тип").Значение;
            // Сохраняем индекс, чтобы потом быстро найти узел в дереве DOM
            НоваяСтрока.ИндексУзла = Индекс;
        КонецЕсли;
    КонецЦикла;
    
    ЧтениеXML.Закрыть();
    УдалитьФайлы(ИмяФайла);
КонецПроцедуры

Теперь, когда пользователь выбирает строку в первой таблице, мы используем событие ПриАктивизацииСтроки или Выбор. В обработчике мы получаем значение ИндексУзла и по нему извлекаем подчиненные свойства.

Способ 2: Использование XDTO для универсального разбора

Если структура XML сложная и многоуровневая, лучше воспользоваться механизмом XDTO. Он позволяет работать с XML как с набором объектов 1С. Рассмотрим рекурсивный метод обхода свойств, который позволяет вывести все вложенные данные документа.

Проанализируем пример кода, который преобразует XML-объект в дерево или таблицу свойств:


&НаСервере
Процедура ПрочитатьСвойстваОбъекта(ОбъектXDTO, РодительскаяСтрока = Неопределено)
    // Если объект является списком (коллекцией)
    Если ТипЗнч(ОбъектXDTO) = Тип("СписокXDTO") Тогда
        Для Каждого ТекущийЭлемент Из ОбъектXDTO Цикл
            НоваяСтр = ТЗ_Свойства.Добавить();
            НоваяСтр.Имя = ОбъектXDTO.ВладеющееСвойство.Имя;
            Если ТипЗнч(ТекущийЭлемент) = Тип("ОбъектXDTO") Тогда
                ПрочитатьСвойстваОбъекта(ТекущийЭлемент, НоваяСтр);
            Иначе
                НоваяСтр.Значение = ТекущийЭлемент;
            КонецЕсли;
        КонецЦикла;
    Иначе
        // Перебор свойств одиночного объекта
        Для Каждого Свойство Из ОбъектXDTO.Свойства() Цикл
            ЗначениеСвойства = ОбъектXDTO.Получить(Свойство);
            НоваяСтр = ТЗ_Свойства.Добавить();
            НоваяСтр.Имя = Свойство.Имя;
            
            Если ТипЗнч(ЗначениеСвойства) = Тип("ОбъектXDTO") ИЛИ ТипЗнч(ЗначениеСвойства) = Тип("СписокXDTO") Тогда
                ПрочитатьСвойстваОбъекта(ЗначениеСвойства, НоваяСтр);
            Иначе
                НоваяСтр.Значение = ЗначениеСвойства;
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
КонецПроцедуры

Этот метод хорош тем, что он «всеяден». Ему не важно, как называются теги внутри документа, он просто обходит всю структуру ОбъектXDTO.Свойства() и выводит их в таблицу. Это идеальное решение для универсальных инструментов просмотра XML.

Оптимизация: XPath и Пространства имен

Выясним причину, по которой код может не находить узлы в некоторых файлах. Часто XML содержит пространства имен (Namespace), например, xmlns:v8="http://v8.1c.ru/data". В этом случае обычное сравнение Узел.ИмяУзла = "Объект" может вернуть Ложь, так как полное имя узла будет содержать префикс.

Рассмотрим использование XPath. Это язык запросов к XML, который позволяет найти узел по условию без циклов. Чтобы XPath работал корректно с DOM, нужно использовать РаспознавательПространствИменDOM.


Распознаватель = Новый РаспознавательПространствИменDOM(ДокументDOM);
РезультатЗапроса = ДокументDOM.ВычислитьВыражениеXPath("//Объект[@Тип='СправочникСсылка.Номенклатура']", 
    ДокументDOM, Распознаватель, ТипРезультатаDOMXPath.УпорядоченныйИтераторУзлов);

Использование XPath значительно ускоряет разработку, позволяя писать короткие и понятные запросы к данным вместо вложенных циклов Для Каждого.

Критически важные замечания по производительности

Разберем ситуацию с большими файлами. Если ваш XML-файл обмена весит более 100-200 Мб, использование ПостроительDOM или ФабрикаXDTO.ПрочитатьXML() может привести к ошибке "Недостаточно памяти". Это происходит потому, что данные методы загружают всю структуру файла в оперативную память в виде объектов.

В таких случаях рекомендуется использовать последовательное чтение:

  1. Применяем ЧтениеXML.Прочитать() в цикле Пока ЧтениеXML.Прочитать() Цикл.
  2. Это потоковое чтение, которое потребляет минимум памяти (только текущий узел).
  3. Для отображения во второй таблице при клике можно либо запоминать смещение в файле, либо (что проще) повторно прочитать файл до нужного вхождения.

Проанализировав вышеописанные подходы, мы видим, что для небольших файлов и удобства разработки лучше всего подходит XDTO или DOM с индексацией, а для высоконагруженных систем — последовательное чтение. Выбор метода зависит от ваших конкретных бизнес-требований и объема обрабатываемых данных.

← На главную