Как исправить загрузку документов перемещения МПЗ из XML в 1С 7.7, если не заполняется табличная часть?

Программист 1С v7.7 Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При интеграции сторонних систем с платформой 1С 7.7 разработчики часто сталкиваются с ситуацией, когда шапка документа загружается корректно, а табличная часть с номенклатурой остается пустой. Проанализируем типичные причины такой ошибки, разберем работу с внешней компонентой v7plus.dll и рассмотрим альтернативный способ чтения XML с использованием COM-объекта MSXML2.DOMDocument.

Выясним причину ошибки обхода узлов XML

Рассмотрим исходный алгоритм чтения XML-файла. Основная проблема при работе с компонентой v7plus.dll возникает из-за смешивания механизмов последовательного считывания (методы Спуститься, Следующий) и работы с объектами DOM (метод ТекущийЭлементВВидеОбъекта).

Когда считыватель подходить к тегу Товары, позиция указателя в файле сбивается. Попытка обратиться к подчиненным узлам без правильного спуска по иерархии тегов приводит к тому, что цикл чтения строк табличной части просто пропускается.

Исходный фрагмент обработки, содержащий логическую ошибку:


ИначеЕсли ( УзелНакладные.Наименование = "Товары" ) Тогда
    ТипТега = ФайлXML.Спуститься;
    Если ИмяТега = "Строка" Тогда
        Объект = ФайлXML.ТекущийЭлементВВидеОбъекта;
        КоличествоЛинийНакладной = Объект.КоличествоПодчиненных;
        // Переменная ИмяТега не обновилась после метода Спуститься, 
        // из-за чего условие не выполняется и строки пролистываются.
    КонецЕсли;
КонецЕсли;

Решение 1. Корректная последовательная навигация по подчиненным узлам

Разберем по шагам, как исправить логику последовательного чтения через v7plus.dll. Нам необходимо при обнаружении тега Товары переключить контекст на текущий элемент как объект и явно получить все подчиненные узлы с именем Строка, а внутри них — реквизиты Номенклатура и Количество.


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

Решение 2. Выборка узлов через DOM-модель компоненты v7plus

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


ИначеЕсли ( УзелНакладные.Наименование = "Товары" ) Тогда
    УзелКорень = Объект.ВыбратьУзел("Товары");
    Товары = УзелКорень.ВыбратьУзлы("Строка");
    
    Для ш = 1 По Товары.КоличествоУзлов Цикл
        ТекТовар = Товары.ПолучитьУзел(ш - 1);
        
        ТЗнач.НоваяСтрока();
        ТЗнач.НомерДок = НомерДок;
        ТЗнач.ДатаДок = ДатаДок;
        ТЗнач.МестоХранения = СкладОтправитель;
        ТЗнач.МестоХраненияВ = СкладПолучатель;
        ТЗнач.Номенклатура = ТекТовар.ВыбратьУзел("Номенклатура").Значение;
        ТЗнач.Количество = Число(ТекТовар.ВыбратьУзел("Количество").Значение);
    КонецЦикла;
КонецЕсли;

Альтернативный вариант: Использование MSXML2.DOMDocument

Использование компоненты v7plus.dll имеет ряд технических ограничений: она зависит от регистрации системных DLL и выгружает всю память процесса при работе с крупными файлами. Альтернативным и более стабильным вариантом является прямое обращение к Windows-объекту MSXML2.DOMDocument через COM-соединение.

Рассмотрим пример загрузки документа «ДвижениеМПЗ» с помощью XPath-запросов:


ДокXML = СоздатьОбъект("MSXML2.DOMDocument");
ДокXML.async = 0;
Если ДокXML.load("c:\Выгрузка.xml") = 0 Тогда
    Предупреждение("Ошибка чтения файла XML!");
    Возврат;
КонецЕсли;

СписокДокументов = ДокXML.selectNodes("//Документ");
Для счДок = 0 По СписокДокументов.length - 1 Цикл
    УзелДок = СписокДокументов.item(счДок);
    
    НомерДок = УзелДок.selectSingleNode("Номер").text;
    ДатаДок = Дата(УзелДок.selectSingleNode("Дата").text);
    СкладОтп = СокрЛП(УзелДок.selectSingleNode("СкладОтправитель").text);
    СкладПол = СокрЛП(УзелДок.selectSingleNode("СкладПолучатель").text);
    
    // Выбираем все строки текущего документа
    СписокСтрок = УзелДок.selectNodes("Товары/Строка");
    Для счСтр = 0 По СписокСтрок.length - 1 Цикл
        УзелСтр = СписокСтрок.item(счСтр);
        ТоварНаименование = СокрЛП(УзелСтр.selectSingleNode("Номенклатура").text);
        КоличествоТовара = Число(УзелСтр.selectSingleNode("Количество").text);
        
        // Добавление данных в ТаблицуЗначений или напрямую в документ 1С
    КонецЦикла;
КонецЦикла;

Важные особенности заполнения документа «ДвижениеМПЗ» в 1С 7.7

При программном создании документов перемещения МПЗ в конфигурации «Производство + Услуги + Бухгалтерия» необходимо учитывать следующие моменты:

  1. Очистка пробельных символов: Значения строк из XML часто содержат переносы или невидимые пробелы. Обязательно применяйте функцию СокрЛП() перед поиском элементов в справочниках Справочник.Материалы или Справочник.МестаХранения.
  2. Разделение документов в цикле: При группировке данных по номерам документов сворачивайте таблицу строк или разделяйте их условием проверки смены номера документа, чтобы табличные части не дублировались во всех созданных документах.
  3. Автоматическое время документа: Используйте метод АвтоВремя() перед операцией Записать(), чтобы документы не записывались на одно и то же время 00:00:00, что критично для партионного учета.
  4. Использование транзакций: Обрабатывайте массивы документов внутри блока НачатьТранзакцию() — ЗафиксироватьТранзакцию() для предотвращения создания частичных данных при возникновении ошибок поиска номенклатуры.
← На главную