Каталог решений - Удобный способ чтения XML

Описание

Пишу как заметку, чтобы самому не потерять , может и другим пригодится.

Есть много разных способов работы с XML файлом, например через последовательных обход или через построение DOM.

Легко гулятся вот такие снипеты про это : https://helpme1c.ru/chtenie-i-zapis-xml-v-yazyke-1s-8-3-8-2-v-primerax

 

Лично мне оба способа доступа к XML не нравятся. Вот решил поделится тем подходом который на мой вкус красивый.

Суть метода в конвертации XML в Соответствие (Функция ПрочитатьXMLВСоответствие) + Хэлпер для удобного чтения из соответствия (Функция ПрочитатьРеквизитСоотвествия).

Листинг :

  Функция ПрочитатьXMLВСоответствие(XML, ТипПоследнегоЭлемента = Неопределено)    
      
      Ветка = Новый Соответствие;
      Значение = "";
      
      Пока XML.Прочитать() Цикл
          ТипУзла = XML.ТипУзла;
          Если ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
              ТипПоследнегоЭлемента = ТипУзлаXML.НачалоЭлемента; 
              Временно = Ветка.Получить(XML.Имя);
              Если Временно = Неопределено Тогда
                  Ветка.Вставить(XML.Имя, ПрочитатьXMLВСоответствие(XML, ТипПоследнегоЭлемента));
              Иначе
                  Если ТипЗнч(Временно) <> Тип("Массив") Тогда
                      Временно=ПреобразоватьВМассив(Временно);
                      Ветка.Вставить(XML.Имя, Временно);
                  КонецЕсли;
                  Временно.Добавить(ПрочитатьXMLВСоответствие(XML, ТипПоследнегоЭлемента));
              КонецЕсли;
          ИначеЕсли ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
              ТипПоследнегоЭлемента = ТипУзлаXML.КонецЭлемента;
              Возврат ?(ЗначениеЗаполнено(Ветка), Ветка, Значение);
          ИначеЕсли ТипУзла = ТипУзлаXML.Текст И Не ТипПоследнегоЭлемента = ТипУзлаXML.Текст Тогда
              ТипПоследнегоЭлемента = ТипУзлаXML.Текст;
              Значение = Значение + XML.Значение;
              XML.Прочитать();
              Возврат Значение;
          КонецЕсли
      КонецЦикла;
      
      Возврат Ветка;
  КонецФункции
  
  
  Функция ПрочитатьРеквизитСоотвествия(Соответствие,Путь,ЗначениеОшибки=Неопределено) Экспорт
      
      МассивРеквизитов = СтрРазделить(Путь,".");
      
      Счетчик = 0;
      Пока Счетчик<МассивРеквизитов.Количество() Цикл
          Элемент = МассивРеквизитов[Счетчик]; 
          Если Лев(Элемент,1)="(" и Прав(Элемент,1)<>")" Тогда
              Счетчик2=Счетчик+1;
              Пока Счетчик2<МассивРеквизитов.Количество() и Прав(МассивРеквизитов[Счетчик],1)<>")" Цикл
                  МассивРеквизитов[Счетчик]=МассивРеквизитов[Счетчик]+"."+МассивРеквизитов[Счетчик2];
                  МассивРеквизитов.Удалить(Счетчик2);
              КонецЦикла;    
          КонецЕсли;
          Элемент = МассивРеквизитов[Счетчик]; 
          Если  Лев(Элемент,1)="(" и Прав(Элемент,1)=")" Тогда
              МассивРеквизитов[Счетчик]=Сред(Элемент,2,СтрДлина(Элемент)-2);
          КонецЕсли;        
          Счетчик=Счетчик+1;
      КонецЦикла;    
      
      Результат=Соответствие;
      Для каждого Реквизит из МассивРеквизитов Цикл
          Индекс=Неопределено;
          лФигурнаяСкобкаНачало=СтрНайти(Реквизит,"[");
          лФигурнаяСкобкаКонец=СтрНайти(Реквизит,"]");
          Если ЗначениеЗаполнено(лФигурнаяСкобкаНачало) и ЗначениеЗаполнено(лФигурнаяСкобкаКонец) Тогда
              Попытка
                  Индекс=Число(Сред(Реквизит,лФигурнаяСкобкаНачало+1,лФигурнаяСкобкаКонец-лФигурнаяСкобкаНачало-1));
                  Реквизит=СтрЗаменить(Реквизит,СтрШаблон("[%1]",Формат(Индекс,"ЧН=0; ЧГ=")),"");
              Исключение
              КонецПопытки;
          КонецЕсли;    
          
          Если ТипЗнч(Результат)=Тип("Соответствие") Тогда
              Результат=Результат.Получить(Реквизит);
          Иначе
              Результат=ЗначениеОшибки;
              Прервать;
          КонецЕсли;
          
          Если ТипЗнч(Результат)=Тип("Массив") и Индекс<>Неопределено и Результат.Количество()>Индекс Тогда
              Результат=Результат[Индекс];
          КонецЕсли;
      КонецЦикла;    
      
      Если Результат=Неопределено Тогда
          Результат=ЗначениеОшибки;
      КонецЕсли;    
      
      Возврат Результат;
      
  КонецФункции    
  
  
  
  Функция ПреобразоватьВМассив(Значение)
      Если ТипЗнч(Значение)<>Тип("Массив") Тогда
          ВременныйМассив=Новый Массив;
          ВременныйМассив.Добавить(Значение);
          Возврат ВременныйМассив
      Иначе
          Возврат Значение
      КонецЕсли;    
  КонецФункции

Пример использования :

  //АдресФайла - Адрес хранилища на сервере куда помещен файл, можно переписать на получение по пути из ФС
  
  Файл = ПолучитьИзВременногоХранилища(АдресФайла);
  Поток = Файл.ОткрытьПотокДляЧтения(); 
  	
  Чтение = Новый ЧтениеXML();
  Чтение.ОткрытьПоток(Поток);
  	
  //Чтение XML в соответствие
  РезультатЧтения = ПрочитатьXMLВСоответствие(Чтение);
  	
  //Примеры произвольного доступа
  ПримерДоступаСФигурнымиСкобками = ПрочитатьРеквизитСоотвествия(РезультатЧтения,"Message.Body.(Документ.РеализацияТоваровУслуг)");
  ПримерДоступаПоИндексу = ПрочитатьРеквизитСоотвествия(РезультатЧтения,"Message.Body.(Документ.РеализацияТоваровУслуг[0]).КлючевыеСвойства.Дата");
  //итд
  
  Чтение.Закрыть();
  Поток.Закрыть();
  

2й параметр у ПрочитатьРеквизитСоотвествия это строка отражающая полный путь до целевого реквизита соответствия

Скобки "()" используются для придания атомарности конструкции внутри скобки. Т.е в примере соответствие ключ будет прямо так и назван "Документ.РеализацияТоваровУслуг"

Скобки "[]" используются для доступа к массиву по индексу.

has been added to your cart:
Оформление заказа