Для работы со сложными с точки зрения сериализации значениями могут использоваться следующие методы «1С:Предприятия» (они же могут использоваться и для простых типов):
Метод ЗаписатьXML() имеет два обязательных параметра. Первый параметр – это объект типа ЗаписьXML, через который осуществляется запись XML, а второй – значение, которое должно быть записано в XML. Необязательные параметры образуют три различных варианта вызова метода.
В простейшем случае параметра три, и в качестве третьего параметра указывается значение перечисления НазначениеТипаXML, определяющее необходимость явного указания типа данных XML в атрибуте xsi:type корневого элемента XML.
У следующего варианта вызова в качестве третьего параметра используется строковое значение, указывается имя корневого элемента XML. При этом подразумевается, что пространство имен не определено. Четвертый параметр – значение типа НазначениеТипаXML, определяющее необходимость явного указания типа данных XML.
И, наконец, у последнего варианта вызова после параметра, указывающего имя корневого элемента XML, появляется еще один параметр – строковое значение, обозначающее пространство имен, к которому относится корневой элемент. Последний параметр по-прежнему имеет тип НазначениеТипаXML.
Рассмотрим пример использования объекта ЗаписатьXML (листинг 6.73).
Листинг 6.73. Пример использования объекта «ЗаписатьXML»
Знач = "Строка такая";
ЗаписатьXML(Зп, Знач);
ЗаписатьXML(Зп, Знач, "Root", НазначениеТипаXML.Явное);
ЗаписатьXML(Зп, Знач, "Root", "urn:some-namespace");
В результате выполнения приведенного кода будет получен следующий XML-фрагмент (листинг 6.74).
Листинг 6.74. Фрагмент XML-документа
<string>Строка такая</string>
<Root xsi:type="xsd:string">Строка такая</Root>
<d1p1:Root xmlns:d1p1="urn:some-namespace">Строка такая</d1p1:Root>
Если в качестве значения, помещаемого в XML, будет передано значение типа, который не может быть представлен в XML, то будет вызвано исключение.
Метод ПрочитатьXML() предназначен для чтения значений из XML. Данный метод имеет один обязательный параметр – объект ЧтениеXML, из которого должно быть прочитано значение. В качестве второго параметра может быть указан тип значения, которое должно быть прочитано из XML. Если тип значения явно указан в XML, то в качестве второго параметра может быть указано значение Неопределено или же он может быть вообще опущен. В этом случае метод ПрочитатьXML() пытается определить тип читаемого значения по содержимому атрибута xsi:type, а если атрибут xsi:type отсутствует – то по имени элемента. Если тип установить не удалось или значение указанного типа не может быть прочитано из XML, то вызывается исключение. При удачном завершении метод ПрочитатьXML() возвращает считанное значение.
Следует обратить внимание на то, как считываются менеджеры значений констант, объекты базы данных и наборы записей. После успешного выполнения чтения метод ПрочитатьXML() возвращает считанное из XML значение, но это значение еще не записано в базу данных. Если, например, считан элемент справочника, то для того, чтобы считанный элемент справочника оказался записанным в базу данных, необходимо обратиться к его методу Записать(), как и при «обычной» записи измененного состояния объекта. Это же относится и к другим объектам базы данных, менеджерам записи констант и наборам записей.
При чтении объекта базы данных из XML в базе данных производится поиск объекта с таким же значением ссылки. Если такой объект найден, то считывание из XML выглядит так, как будто объект был прочитан из базы данных, после чего значения его реквизитов, табличных частей и т. п. перезаписываются полученными из XML значениями. Если же объект по ссылке не найден, то считывание из XML выглядит как создание нового объекта, установка ему значения ссылки и заполнение его содержимого значениями, прочитанными из XML.
Метод ВозможностьЧтенияXML() определяет, возможно ли считывание значения из объекта ЧтениеXML, находящегося в текущей позиции документа XML. Объект ЧтениеXML передается данному методу в качестве параметра. Если метод возвращает Истина, то чтение возможно, если Ложь – значение не может быть считано.
Метод ПолучитьXMLТип() позволяет получить из объекта ЧтениеXML тип данных XML, соответствующий текущей позиции документа XML. Данный метод также имеет один параметр – ЧтениеXML.
Рассмотрим использование вышеперечисленных методов на примере. В контексте процедуры ЗаписьСложныхТиповДанных() существует переменная Документ (тип ДокументСсылка.<имя>). Данный документ имеет следующую структуру:
Следует отметить, что метод ЗаписатьXML() сам определяет структуру выгружаемого объекта. В данном случае она приводится, для того чтобы пояснить полученный XML-документ.
При записи и чтении сложных типов XML данных так же, как это подробно описано в разделе «», передача XML-документа между клиентом и сервером происходит через временное хранилище.
Для записи сложных типов XML может использоваться следующий программный код (листинги 6.75, 6.76).
Листинг 6.75. Пример записи XML-документа
&НаКлиенте
Процедура ЗаписьСложныхТиповДанных(Команда)
АдресДокументаВХранилище = ЗаписьСложныхДанныхXML();
НачатьПолучениеФайлаССервера(, АдресДокументаВХранилище, "c:\temp\example3.xml");
КонецПроцедуры
Листинг 6.76. Функция «ЗаписьСложныхДанныхXML()»
&НаСервереБезКонтекста
Функция ЗаписьСложныхДанныхXML()
ИмяФайлаXML = КаталогВременныхФайлов() + "temp.xml";
Файл = Новый ЗаписьXML;
Файл.ОткрытьФайл(ИмяФайлаXML);
Файл.ЗаписатьОбъявлениеXML();
// Получить ссылку на документ.
СсылкаНаДокумент = Документы.РасходнаяНакладная.НайтиПоНомеру("000000001");
ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
ЗаписатьXML(Файл, ДокументОбъект, НазначениеТипаXML.Явное);
Файл.Закрыть();
Возврат ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяФайлаXML));
КонецФункции
Заметим, что в этом примере используется другой (по сравнению с предыдущим примером) вариант вызова метода НачатьПолучениеФайлаССервера() – с указанием имени получаемого файла. При этом пользователь не имеет возможности выбрать имя и расположение сохраняемого файла.
В результате работы процедуры сформируется XML-документ следующего вида (листинг 6.77).
Листинг 6.77. Пример сформированного XML-документа
<?xml version="1.0" encoding="UTF-8"?>
<DocumentObject.РасходнаяНакладная xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="DocumentObject.РасходнаяНакладная">
<Ref>564baba3-9c2b-11e9-8e83-642737df2048</Ref>
<DeletionMark>false</DeletionMark>
<Date>2019-06-17T00:00:00</Date>
<Number>000000001</Number>
<Posted>false</Posted>
<Клиент>ba552984-9393-11e9-be71-642737df2048</Клиент>
<Основание>Заказ 000000001 от 17.06.2019 12:00:00</Основание>
<Товары>
<Row>
<Товар>ba552988-9393-11e9-be71-642737df2048</Товар>
<Количество>2</Количество>
<Цена>3000</Цена>
<Сумма>6000</Сумма>
</Row>
<Row>
<Товар>ba552987-9393-11e9-be71-642737df2048</Товар>
<Количество>1</Количество>
<Цена>5000</Цена>
<Сумма>5000</Сумма>
</Row>
</Товары>
</DocumentObject.РасходнаяНакладная>
Можно сказать, что структура выгруженного документа повторяет структуру его метаданных, причем дополнительно включаются такие данные, как:
Для чтения выгруженного XML-документа (см. листинг 6.77) может использоваться следующий программный код (листинг 6.78).
Листинг 6.78. Процедура чтения XML-документа
&НаКлиенте
Процедура ЧтениеСложныхТиповДанных(Команда)
АдресВременногоХранилища = "";
ОповещениеОЗавершении = Новый ОписаниеОповещения("ЧтениеСложныхТиповДанныхЗавершение", ЭтотОбъект);
НачатьПомещениеФайлаНаСервер(ОповещениеОЗавершении, , , АдресВременногоХранилища, "c:\temp\example2.xml",
УникальныйИдентификатор);
КонецПроцедуры
Заметим, что в этом примере используется другой (по сравнению с предыдущим примером) вариант вызова метода НачатьПомещениеФайлаНаСервер() – с указанием имени помещаемого файла. При этом пользователю не показывается диалог выбора файла.
В метод НачатьПомещениеФайлаНаСервер() первым параметром передается описание оповещения, указывающее на экспортную процедуру ЧтениеСложныхТиповДанныхЗавершение(), которая будет выполнена, после того,как файл с данными XML будет помещен во временное хранилище (листинг 6.79).
Листинг 6.79. Процедура «ЧтениеСложныхТиповДанныхЗавершение()»
&НаКлиенте
Процедура ЧтениеПростыхТиповДанныхЗавершение(ОписаниеПомещенногоФайла, Дополнительно) Экспорт
ЧтениеСложныхДанныхXML(ОписаниеПомещенногоФайла.Адрес);
КонецПроцедуры
После того как файл будет помещен, вызывается серверная процедура ЧтениеСложныхДанныхXML(), в которую передается адрес помещенного файла во временном хранилище. В этой процедуре и производится, собственно, чтение документа (листинг 6.80).
Листинг 6.80. Процедура «ЧтениеСложныхДанныхXML()»
&НаСервереБезКонтекста
Процедура ЧтениеСложныхДанныхXML(АдресДокументаВХранилище)
ДанныеДокумента = ПолучитьИзВременногоХранилища(АдресДокументаВХранилище);
ИмяФайлаXML = КаталогВременныхФайлов() + "temp.xml";
ДанныеДокумента.Записать(ИмяФайлаXML);
Файл = Новый ЧтениеXML;
Файл.ОткрытьФайл(ИмяФайлаXML);
// Спозиционироваться на начале элемента, содержащего документ.
Если Файл.Прочитать() Тогда
// Проверить возможность чтения значения.
Если ВозможностьЧтенияXML(Файл) Тогда
// Получить значение ДокументОбъект.Имя
Объект = ПрочитатьXML(Файл);
Объект.Дата = '2020-01-31';
Объект.Записать();
КонецЕсли;
КонецЕсли;
Файл.Закрыть();
КонецПроцедуры
Следует отметить, что если объект, в который производится загрузка, имеет отличную от выгружаемого объекта структуру (отличается состав реквизитов, табличных частей, реквизитов табличных частей или порядок их следования), то метод ВозможностьЧтенияXML() может возвратить значение Истина. При попытке проведения чтения объекта из XML-документа будет вызвано исключение. Это объясняется тем, что метод ВозможностьЧтенияXML() анализирует текущее состояние объекта ЧтениеXML. В этот момент текущим является начало соответствующего элемента. Если имя элемента, атрибуты «понятны» методу, он и возвращает значение Истина. Проверка структуры, других моментов методом ВозможностьЧтенияXML() не производится.