Загрузка XML в дерево значений

Случайно наткнулся на статью с алгоритмом загрузки XML-строки в дерево значений и подумал, а не проще ли сделать это через механизм XDTO рекурсивно. На мой взгляд, решение получилось неплохое — даже атрибуты грузит..

Добрый всем день, ночь и прочие времена суток, когда 1С-ники читают данный сайт.

Иногда (может даже часто) нужно загрузить XML в дерево значений. Вот как можно это сделать через механизм XDTO:

Процедура ПоместитьВДерево(Текст)
Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(Текст);
Об = ФабрикаXDTO.ПрочитатьXML(Чтение);

Строка = Дерево.ПолучитьЭлементы().Добавить();
Строка.Узел = "Корневой узел";
ПрочитатьУзел(Об, Строка);
КонецПроцедуры

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

В данном случае у нас на управляемой форме есть дерево с двумя строковыми колонками «Узел» и «Значение». В процедуру «ПоместитьВДерево» нужно передать текст прочитанного XML-файла, после чего оный загрузится в дерево значений.

24 Comments

  1. Поручик

    Довольно просто для клиента. На сервере будет работать? Ведь строго говоря, вы читаете XML не в дерево значений, а в реквизит формы ДанныеФормыДерево

    Reply
  2. starik-2005

    Это серверные процедуры. Просто в дерево тоже можно прочитать немного изменив код.

    Reply
  3. karpik666

    (2) starik-2005, может они и серверные, но явно в коде используется данныеФормыДерево, а не дерево значений, поэтому ваш код будет работать только в контексте вызываемой формы, но не в общем модуле.

    Reply
  4. starik-2005

    (3) karpik666, ну это чтобы у читателей была возможность подумать. Я за светлое коммунистическое будущее мыслителей и творцов, а не за общество потребительского кредитования…

    Reply
  5. genayo

    Вот такой XML, не загружаются значения, только атрибуты:

    <Table:Record name=»CustPickingExportDC» row=»1″>

    <Table:Field name=»SalesId»>ФН000000053</Table:Field>

    <Table:Field name=»PickingListId»>ФН000000053</Table:Field>

    <Table:Field name=»CustAccount»>000000661</Table:Field>

    <Table:Field name=»ConsigneeAccount»>000000755</Table:Field>

    <Table:Field name=»InventLocationId»/>

    <Table:Field name=»DeliveryDate»>2016-11-23</Table:Field>

    <Table:Field name=»ManDate»/>

    <Table:Field name=»ItemId»>ББ00065B125</Table:Field>

    <Table:Field name=»InventQty»>3</Table:Field>

    <Table:Field name=»SalesUnit»>кг</Table:Field>

    <Table:Field name=»SalesQty»>18</Table:Field>

    </Table:Record>

    Reply
  6. starik-2005

    (5) genayo, да, при наличии «Namespace prefix» файл не грузится. Но если его убрать, то все работает:

    Также заметил, что при наличии атрибутов у элемента и значение элемента — строка, а не вложенный контейнер, то я не нашел, как получить текст самого элемента у XDTO.

    Reply
  7. cartograph

    Так ведь было уже: http://infostart.ru/public/414940/

    Reply
  8. starik-2005

    (7) cartograph, ну там просто чтение, а тут в дерево раскладывает прочитанное рекурсивненько. Не чувствуете разницу?

    Reply
  9. infostart user

    рекурсия, вложенные циклы — есть куда оптимизировать. кажись уже такие штуки на инфостарте не раз публиковали

    Reply
  10. starik-2005

    (9) infostart user, в данном конкретном случае оптимизировать, поверьте, особо некуда — вложенные циклы тут как раз уместны. А рекурсия — это вообще один из немногих способов организовать цикл в функциональном программировании, хотя, конечно, 1С тут в плане функциональности весьма ограничена.

    Но если Вы предложите вариант оптимизации — велкам! ))

    Reply
  11. genayo

    (6) Вот и я не нашел как чисто через фабрику XDTO такой XML прочитать, пришлось использовать комбинацию XDTO и DOM, что на больших файлах несколько печально. Может, есть идеи как проще такой XML прочитать?

    Reply
  12. starik-2005

    (11) как показал гугл, такая возможность есть. Видел в паре источников — сейчас не вспомню, в каких.

    Reply
  13. boln
    Случайно наткнулся на статью с алгоритмом загрузки XML-строки в дерево значений

    Не на эту, случайно?

    http://infostart.ru/public/14610/

    Reply
  14. starik-2005

    (13)

    Не на эту, случайно?

    Неа.

    Reply
  15. starik-2005

    Господа, внезапно узнал, как получить текст элемента при наличии атрибутов из объекта XDTO. Если интересно — могу написать еще одну статью на эту тему.

    Reply
  16. МихаилМ

    (15) также интересно через xslt

    Reply
  17. rozer

    можно проще просто последовательно читать

    код в форме

    
    &НаКлиенте
    Процедура ЗагрузитьФайл(Команда)
    Длг = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Длг.Показать(Новый ОписаниеОповещения(«ПриВыбореФайла», ЭтаФорма, «Открыть»));
    КонецПроцедуры
    
    &НаКлиенте
    Процедура ПриВыбореФайла(Результат, ДопПараметры) Экспорт
    Если НЕ Результат = Неопределено Тогда
    ЧтениеXMLВДерево(Результат[0])
    КонецЕсли;
    КонецПроцедуры
    
    &НаСервере
    Функция ЧтениеXMLВДерево(Путь)
    XMLФайл = Новый ЧтениеXML;
    XMLФайл.ОткрытьФайл(Путь);
    ОбъектОбработка = РеквизитФормыВЗначение(«Объект»);
    ОбъектОбработка.ПрочитатьXMLПоТегам(XMLФайл, ОбъектОбработка.Дерево.Строки);
    ЗначениеВРеквизитФормы(ОбъектОбработка, «Объект»);
    XMLФайл.Закрыть();
    КонецФункции
    
    

    Показать

    код в модуле

    Процедура ПрочитатьXMLПоТегам(XMLФайл, ТекущийНаборСтрок) Экспорт
    Пока XMLФайл.Прочитать() Цикл
    Если XMLФайл.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
    
    НоваяСтрока = ТекущийНаборСтрок.Добавить();
    НоваяСтрока.Имя = XMLФайл.Имя;
    НоваяСтрока.Значение = «»;
    Пока XMLФайл.ПрочитатьАтрибут() Цикл
    НоваяСтрокаАтрибут = НоваяСтрока.Строки.Добавить();
    НоваяСтрокаАтрибут.Имя = XMLФайл.Имя;
    НоваяСтрокаАтрибут.Значение = СокрЛП(XMLФайл.Значение);
    КонецЦикла;
    ПрочитатьXMLПоТегам(XMLФайл, НоваяСтрока.Строки);
    
    ИначеЕсли XMLФайл.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
    
    Возврат;
    
    ИначеЕсли XMLФайл.ТипУзла = ТипУзлаXML.Текст Тогда
    
    ТекущийНаборСтрок.Родитель.Значение = СокрЛП(XMLФайл.Значение);
    
    Иначе
    
    Сообщить(«Тип узла: » + XMLФайл.ТипУзла + » НЕ ОБРАБОТАН», СтатусСообщения.Важное);
    
    Конецесли;
    КонецЦикла;
    КонецПроцедуры
    

    Показать

    и еще ваш код при более чем одном узле зачем-то лепит лишнюю строку

    результат разбора

    файл

    Reply
  18. starik-2005

    (17)

    можно проще просто последовательно читать

    На Инфостарте масса обработок, которые делают подобное.

    По поводу текущей обработки, то она рекурсивно преобразует в дерево именно прочитанный XDTO-объект.

    По поводу списка, то, полагаю, нужно посмотреть, как прочитался сам файл в объект XDTO.. У меня в коде при наличии списка XDTO в свойстве это свойство сначала создается. Решить можно просто — проверять, что в свойстве список и не создавать для него отдельную ветку дерева, а разворачивать в текущую.

    Reply
  19. rozer

    (18)

    Решить можно просто — проверять, что в свойстве список и не создавать для него отдельную ветку дерева, а разворачивать в текущую.

    это понятно ) просто думал бага а это фича )

    Reply
  20. kasper076

    (11) нужно создать правильный пакет XDTO. Например такой, как во вложении. В нем значение элемента имеет тип число, а атрибут строка.

    Reply
  21. RocKeR_13
    В данном случае у нас на управляемой форме есть дерево с двумя строковыми колонками «Узел» и «Значение».

    Ну судя по коду и скрину должно быть

    «Узел» и «Элемент»

    Больше придирка, а по делу — спасибо)

    Reply
  22. starik-2005

    (21)

    Ну судя по коду и скрину должно быть

    Истину глаголишь )))

    Reply
  23. gnom13

    Почему то тут не принимают во внимание что если у вас серверная база данных то это работать не будет.

    &НаКлиенте
    Процедура ПриВыбореФайла(Результат, ДопПараметры) Экспорт
    Если НЕ Результат = Неопределено Тогда
    ЧтениеXMLВДерево(Результат[0])
    КонецЕсли;
    КонецПроцедуры

    В этой процедуре Результат[0] передаётся с клиентской машины. На сервере этого пути не будет Выдаст ошибку.

    Reply
  24. starik-2005

    (23)

    В этой процедуре Результат[0] передаётся с клиентской машины. На сервере этого пути не будет Выдаст ошибку.

    На сервере нет, но данная процедура, если мне не изменяет память, клиентская, которая читает текст и передает его в:

    Процедура ПоместитьВДерево(Текст)
    Чтение = Новый ЧтениеXML;
    Чтение.УстановитьСтроку(Текст);
    Об = ФабрикаXDTO.ПрочитатьXML(Чтение);
    
    Строка = Дерево.ПолучитьЭлементы().Добавить();
    Строка.Узел = «Корневой узел»;
    ПрочитатьУзел(Об, Строка);
    КонецПроцедуры

    Показать

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *