Разбор представления объекта xml. Процедура считывает данные XML из файла и заполняет структуры данных.
// Процедура считывает данные XML из файла и заполняет структуры данных.
//
// Возвращаемое значение:
// Структура, содержащая два соответствия: ТабличныеЧасти, Реквизиты.
// Структура хранения данных:
// Соответствие ТабличныеЧасти, которое содержит в себе значения табличных частей
// формат:
// СоответствиеИмя1 -> ТаблицаЗначений1
// | | ... |
// Поле1 Поле2 ПолеM1.
//
// СоответствиеИмя2 -> ТаблицаЗначений2
// | | ... |
// Поле1 Поле2 ПолеM2.
//
//
// СоответствиеИмяN -> ТаблицаЗначенийN
// | | ... |
// Поле1 Поле2 ПолеM3.
//
// Соответствие ЗначенияРеквизитов
// ИмяРеквизита1 -> Значение1
// ИмяРеквизита2 -> Значение2
// ...
// ИмяРеквизитаN -> ЗначениеN.
//
Функция РазборПредставленияОбъектаXML(ДанныеВерсии, Ссылка) Экспорт
Результат = Новый Структура;
Результат.Вставить("ТабличныеДокументы");
Результат.Вставить("ДополнительныеРеквизиты");
Результат.Вставить("СкрываемыеРеквизиты", Новый Массив);
ДвоичныеДанные = ДанныеВерсии;
Если ТипЗнч(ДанныеВерсии) = Тип("Структура") Тогда
ДвоичныеДанные = ДанныеВерсии.Объект;
ДанныеВерсии.Свойство("ТабличныеДокументы", Результат.ТабличныеДокументы);
ДанныеВерсии.Свойство("ДополнительныеРеквизиты", Результат.ДополнительныеРеквизиты);
ДанныеВерсии.Свойство("СкрываемыеРеквизиты", Результат.СкрываемыеРеквизиты);
КонецЕсли;
ЗначенияРеквизитов = Новый ТаблицаЗначений;
ЗначенияРеквизитов.Колонки.Добавить("НаименованиеРеквизита");
ЗначенияРеквизитов.Колонки.Добавить("ЗначениеРеквизита");
ЗначенияРеквизитов.Колонки.Добавить("ТипРеквизита");
ЗначенияРеквизитов.Колонки.Добавить("Тип");
ТабличныеЧасти = Новый Соответствие;
ЧтениеXML = Новый ЧтениеFastInfoSet;
ЧтениеXML.УстановитьДвоичныеДанные(ДвоичныеДанные);
// Уровень позиции маркера в иерархии XML:
// 0 - уровень не задан
// 1 - первый элемент (имя объекта)
// 2 - описание реквизита или табличной части
// 3 - описание строки табличной части
// 4 - описание поля строки табличной части.
УровеньЧтения = 0;
МетаданныеОбъекта = Ссылка.Метаданные();
ТипЗначенияПоляТЧ = "";
// Основной цикл разбора по XML.
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
УровеньЧтения = УровеньЧтения + 1;
Если УровеньЧтения = 1 Тогда // Указатель на первом элементе XML - корень XML.
// В ЧтениеXML.Имя имя объекта, но оно нам не нужно.
ИначеЕсли УровеньЧтения = 2 Тогда // Указатель на втором уровне - это реквизит или имя табличной части.
ИмяРеквизита = ЧтениеXML.Имя;
// Любой реквизит "может оказаться" табличной частью, поэтому на всякий случай его запомним.
ИмяТабличнойЧасти = ИмяРеквизита;
Если МетаданныеТабличнойЧасти(МетаданныеОбъекта, ИмяТабличнойЧасти) <> Неопределено Тогда
ТабличныеЧасти.Вставить(ИмяТабличнойЧасти, Новый ТаблицаЗначений);
КонецЕсли;
НовоеЗР = ЗначенияРеквизитов.Добавить();
НовоеЗР.НаименованиеРеквизита = ИмяРеквизита;
Если ЧтениеXML.КоличествоАтрибутов() > 0 Тогда
Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.Атрибут
И ЧтениеXML.Имя = "xsi:type" Тогда
НовоеЗР.ТипРеквизита = ЧтениеXML.Значение;
XMLТип = ЧтениеXML.Значение;
Если СтрНачинаетсяС(XMLТип, "xs:") Тогда
НовоеЗР.Тип = ИзXMLТипа(Новый ТипДанныхXML(Прав(XMLТип, СтрДлина(XMLТип)-3), "http://www.w3.org/2001/XMLSchema"));
Иначе
НовоеЗР.Тип = ИзXMLТипа(Новый ТипДанныхXML(XMLТип, ""));
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если Не ЗначениеЗаполнено(НовоеЗР.Тип) Тогда
ОписаниеРеквизита = МетаданныеРеквизита(МетаданныеОбъекта, ИмяРеквизита);
Если ОписаниеРеквизита = Неопределено Тогда
ОписаниеРеквизита = Метаданные.ОбщиеРеквизиты.Найти(ИмяРеквизита);
КонецЕсли;
Если ОписаниеРеквизита = Неопределено И Метаданные.ПланыСчетов.Содержит(МетаданныеОбъекта) Тогда
ОписаниеРеквизита = МетаданныеОбъекта.ПризнакиУчета.Найти(ИмяРеквизита);
КонецЕсли;
Если ОписаниеРеквизита <> Неопределено
И ОписаниеРеквизита.Тип.Типы().Количество() = 1 Тогда
НовоеЗР.Тип = ОписаниеРеквизита.Тип.Типы()[0];
КонецЕсли;
КонецЕсли;
ИначеЕсли (УровеньЧтения = 3) И ЧтениеXML.Имя = "Row" Тогда // Указатель на поле табличной части.
Если ТабличныеЧасти[ИмяТабличнойЧасти] = Неопределено Тогда
ТабличныеЧасти.Вставить(ИмяТабличнойЧасти, Новый ТаблицаЗначений);
КонецЕсли;
ТабличныеЧасти[ИмяТабличнойЧасти].Добавить();
ИначеЕсли УровеньЧтения = 4 Тогда
Если ЧтениеXML.Имя = "v8:Type" Тогда
Если НовоеЗР.ЗначениеРеквизита = Неопределено Тогда
НовоеЗР.ЗначениеРеквизита = "";
КонецЕсли;
Иначе // Указатель на поле табличной части.
ТипЗначенияПоляТЧ = "";
ИмяПоляТЧ = ЧтениеXML.Имя;
Таблица = ТабличныеЧасти[ИмяТабличнойЧасти];
Если Таблица.Колонки.Найти(ИмяПоляТЧ)= Неопределено Тогда
Таблица.Колонки.Добавить(ИмяПоляТЧ);
КонецЕсли;
Если ЧтениеXML.КоличествоАтрибутов() > 0 Тогда
Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.Атрибут
И ЧтениеXML.Имя = "xsi:type" Тогда
XMLТип = ЧтениеXML.Значение;
Если СтрНачинаетсяС(XMLТип, "xs:") Тогда
ТипЗначенияПоляТЧ = ИзXMLТипа(Новый ТипДанныхXML(Прав(XMLТип, СтрДлина(XMLТип)-3), "http://www.w3.org/2001/XMLSchema"));
Иначе
ТипЗначенияПоляТЧ = ИзXMLТипа(Новый ТипДанныхXML(XMLТип, ""));
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецЕсли;
ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
УровеньЧтения = УровеньЧтения - 1;
ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
Если (УровеньЧтения = 2) Тогда // значение реквизита
Попытка
НовоеЗР.ЗначениеРеквизита = ?(ЗначениеЗаполнено(НовоеЗР.Тип), XMLЗначение(НовоеЗР.Тип, ЧтениеXML.Значение), ЧтениеXML.Значение);
Исключение
НовоеЗР.ЗначениеРеквизита = ЧтениеXML.Значение;
КонецПопытки;
ИначеЕсли (УровеньЧтения = 4) Тогда // значение реквизита
Если НовоеЗР.Тип = Тип("ОписаниеТипов") Тогда
ТипСтрокой = Строка(ИзXMLТипа(Новый ТипДанныхXML(ЧтениеXML.Значение, "")));
Если ПустаяСтрока(ТипСтрокой) Тогда
ТипСтрокой = ЧтениеXML.Значение;
КонецЕсли;
Если Не ПустаяСтрока(НовоеЗР.ЗначениеРеквизита) Тогда
НовоеЗР.ЗначениеРеквизита = НовоеЗР.ЗначениеРеквизита + Символы.ПС;
КонецЕсли;
НовоеЗР.ЗначениеРеквизита = НовоеЗР.ЗначениеРеквизита + ТипСтрокой;
Иначе
Если ТипЗначенияПоляТЧ = "" Тогда
ОписаниеРеквизита = Неопределено;
МетаданныеТабличнойЧасти = МетаданныеТабличнойЧасти(МетаданныеОбъекта, ИмяТабличнойЧасти);
Если МетаданныеТабличнойЧасти <> Неопределено Тогда
ОписаниеРеквизита = МетаданныеРеквизитаТабличнойЧасти(МетаданныеТабличнойЧасти, ИмяПоляТЧ);
Если ОписаниеРеквизита = Неопределено И Метаданные.ПланыСчетов.Содержит(МетаданныеОбъекта) Тогда
ОписаниеРеквизита = МетаданныеОбъекта.ПризнакиУчетаСубконто.Найти(ИмяПоляТЧ);
КонецЕсли;
Если ОписаниеРеквизита <> Неопределено
И ОписаниеРеквизита.Тип.Типы().Количество() = 1 Тогда
ТипЗначенияПоляТЧ = ОписаниеРеквизита.Тип.Типы()[0];
КонецЕсли;
КонецЕсли;
КонецЕсли;
ПоследняяСтрока = ТабличныеЧасти[ИмяТабличнойЧасти].Получить(ТабличныеЧасти[ИмяТабличнойЧасти].Количество()-1);
ПоследняяСтрока[ИмяПоляТЧ] = ?(ЗначениеЗаполнено(ТипЗначенияПоляТЧ), XMLЗначение(ТипЗначенияПоляТЧ, ЧтениеXML.Значение), ЧтениеXML.Значение);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Из списка реквизитов исключаем табличные части.
Для Каждого Элемент Из ТабличныеЧасти Цикл
ЗначенияРеквизитов.Удалить(ЗначенияРеквизитов.Найти(Элемент.Ключ));
КонецЦикла;
// Заполнение колонок таблицы в случае, когда в объекте табличная часть пустая, и имена колонок не были прочитаны.
Для Каждого ТабличнаяЧасть Из ТабличныеЧасти Цикл
ИмяТаблицы = ТабличнаяЧасть.Ключ;
Таблица = ТабличнаяЧасть.Значение;
Если Таблица.Колонки.Количество() = 0 Тогда
МетаданныеТаблицы = МетаданныеТабличнойЧасти(МетаданныеОбъекта, ИмяТаблицы);
Если МетаданныеТаблицы <> Неопределено Тогда
Для Каждого ОписаниеКолонки Из РеквизитыТабличнойЧасти(МетаданныеТаблицы) Цикл
Если Таблица.Колонки.Найти(ОписаниеКолонки.Имя)= Неопределено Тогда
Таблица.Колонки.Добавить(ОписаниеКолонки.Имя);
КонецЕсли;
КонецЦикла;
Если Метаданные.ПланыСчетов.Содержит(МетаданныеОбъекта) Тогда
Для Каждого ОписаниеКолонки Из МетаданныеОбъекта.ПризнакиУчетаСубконто Цикл
Если Таблица.Колонки.Найти(ОписаниеКолонки.Имя)= Неопределено Тогда
Таблица.Колонки.Добавить(ОписаниеКолонки.Имя);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Результат.Вставить("Реквизиты", ЗначенияРеквизитов);
Результат.Вставить("ТабличныеЧасти", ТабличныеЧасти);
Если Результат.СкрываемыеРеквизиты <> Неопределено Тогда
Для Каждого ИмяРеквизита Из Результат.СкрываемыеРеквизиты Цикл
Если СтрЗаканчиваетсяНа(ИмяРеквизита, ".*") Тогда
ИмяТабличнойЧасти = Лев(ИмяРеквизита, СтрДлина(ИмяРеквизита) - 2);
Если Результат.ТабличныеЧасти[ИмяТабличнойЧасти] <> Неопределено Тогда
Результат.ТабличныеЧасти.Удалить(ИмяТабличнойЧасти);
КонецЕсли;
Иначе
НайденныеРеквизиты = Результат.Реквизиты.НайтиСтроки(Новый Структура("НаименованиеРеквизита", ИмяРеквизита));
Для Каждого Реквизит Из НайденныеРеквизиты Цикл
Результат.Реквизиты.Удалить(Реквизит);
КонецЦикла;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если Результат.ДополнительныеРеквизиты <> Неопределено Тогда
Для Каждого ДополнительныйРеквизит Из Результат.ДополнительныеРеквизиты Цикл
Реквизит = ЗначенияРеквизитов.Добавить();
Реквизит.НаименованиеРеквизита = ДополнительныйРеквизит.Наименование;
Реквизит.ЗначениеРеквизита = ДополнительныйРеквизит.Значение;
Реквизит.Тип = ТипЗнч(ДополнительныйРеквизит.Значение);
КонецЦикла;
КонецЕсли;
Возврат Результат;
КонецФункции
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2019, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////
ПослеРазбораВерсииОбъекта (БСП)
ПросклонятьПредставление (БСП)
ПредставлениеПроблемногоОбъекта (БСП)
ПредставлениеСпискаОбъектов (БСП)
ПредставлениеОбъектаМетаданных (БСП)